3f388de39983a883af97f724da79f72e78e334e7
[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 /*< private >
7956  * _clutter_actor_get_effective_x_align:
7957  * @self: a #ClutterActor
7958  *
7959  * Retrieves the effective horizontal alignment, taking into
7960  * consideration the text direction of @self.
7961  *
7962  * Return value: the effective horizontal alignment
7963  */
7964 ClutterActorAlign
7965 _clutter_actor_get_effective_x_align (ClutterActor *self)
7966 {
7967   return effective_align (clutter_actor_get_x_align (self),
7968                           clutter_actor_get_text_direction (self));
7969 }
7970
7971 static inline void
7972 adjust_for_margin (float  margin_start,
7973                    float  margin_end,
7974                    float *minimum_size,
7975                    float *natural_size,
7976                    float *allocated_start,
7977                    float *allocated_end)
7978 {
7979   *minimum_size -= (margin_start + margin_end);
7980   *natural_size -= (margin_start + margin_end);
7981   *allocated_start += margin_start;
7982   *allocated_end -= margin_end;
7983 }
7984
7985 static inline void
7986 adjust_for_alignment (ClutterActorAlign  alignment,
7987                       float              natural_size,
7988                       float             *allocated_start,
7989                       float             *allocated_end)
7990 {
7991   float allocated_size = *allocated_end - *allocated_start;
7992
7993   switch (alignment)
7994     {
7995     case CLUTTER_ACTOR_ALIGN_FILL:
7996       /* do nothing */
7997       break;
7998
7999     case CLUTTER_ACTOR_ALIGN_START:
8000       /* keep start */
8001       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
8002       break;
8003
8004     case CLUTTER_ACTOR_ALIGN_END:
8005       if (allocated_size > natural_size)
8006         {
8007           *allocated_start += (allocated_size - natural_size);
8008           *allocated_end = *allocated_start + natural_size;
8009         }
8010       break;
8011
8012     case CLUTTER_ACTOR_ALIGN_CENTER:
8013       if (allocated_size > natural_size)
8014         {
8015           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
8016           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
8017         }
8018       break;
8019     }
8020 }
8021
8022 /*< private >
8023  * clutter_actor_adjust_width:
8024  * @self: a #ClutterActor
8025  * @minimum_width: (inout): the actor's preferred minimum width, which
8026  *   will be adjusted depending on the margin
8027  * @natural_width: (inout): the actor's preferred natural width, which
8028  *   will be adjusted depending on the margin
8029  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
8030  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
8031  *
8032  * Adjusts the preferred and allocated position and size of an actor,
8033  * depending on the margin and alignment properties.
8034  */
8035 static void
8036 clutter_actor_adjust_width (ClutterActor *self,
8037                             gfloat       *minimum_width,
8038                             gfloat       *natural_width,
8039                             gfloat       *adjusted_x1,
8040                             gfloat       *adjusted_x2)
8041 {
8042   ClutterTextDirection text_dir;
8043   const ClutterLayoutInfo *info;
8044
8045   info = _clutter_actor_get_layout_info_or_defaults (self);
8046   text_dir = clutter_actor_get_text_direction (self);
8047
8048   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
8049
8050   /* this will tweak natural_width to remove the margin, so that
8051    * adjust_for_alignment() will use the correct size
8052    */
8053   adjust_for_margin (info->margin.left, info->margin.right,
8054                      minimum_width, natural_width,
8055                      adjusted_x1, adjusted_x2);
8056
8057   adjust_for_alignment (effective_align (info->x_align, text_dir),
8058                         *natural_width,
8059                         adjusted_x1, adjusted_x2);
8060 }
8061
8062 /*< private >
8063  * clutter_actor_adjust_height:
8064  * @self: a #ClutterActor
8065  * @minimum_height: (inout): the actor's preferred minimum height, which
8066  *   will be adjusted depending on the margin
8067  * @natural_height: (inout): the actor's preferred natural height, which
8068  *   will be adjusted depending on the margin
8069  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
8070  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
8071  *
8072  * Adjusts the preferred and allocated position and size of an actor,
8073  * depending on the margin and alignment properties.
8074  */
8075 static void
8076 clutter_actor_adjust_height (ClutterActor *self,
8077                              gfloat       *minimum_height,
8078                              gfloat       *natural_height,
8079                              gfloat       *adjusted_y1,
8080                              gfloat       *adjusted_y2)
8081 {
8082   const ClutterLayoutInfo *info;
8083
8084   info = _clutter_actor_get_layout_info_or_defaults (self);
8085
8086   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
8087
8088   /* this will tweak natural_height to remove the margin, so that
8089    * adjust_for_alignment() will use the correct size
8090    */
8091   adjust_for_margin (info->margin.top, info->margin.bottom,
8092                      minimum_height, natural_height,
8093                      adjusted_y1,
8094                      adjusted_y2);
8095
8096   /* we don't use effective_align() here, because text direction
8097    * only affects the horizontal axis
8098    */
8099   adjust_for_alignment (info->y_align,
8100                         *natural_height,
8101                         adjusted_y1,
8102                         adjusted_y2);
8103
8104 }
8105
8106 /* looks for a cached size request for this for_size. If not
8107  * found, returns the oldest entry so it can be overwritten */
8108 static gboolean
8109 _clutter_actor_get_cached_size_request (gfloat         for_size,
8110                                         SizeRequest   *cached_size_requests,
8111                                         SizeRequest  **result)
8112 {
8113   guint i;
8114
8115   *result = &cached_size_requests[0];
8116
8117   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
8118     {
8119       SizeRequest *sr;
8120
8121       sr = &cached_size_requests[i];
8122
8123       if (sr->age > 0 &&
8124           sr->for_size == for_size)
8125         {
8126           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8127           *result = sr;
8128           return TRUE;
8129         }
8130       else if (sr->age < (*result)->age)
8131         {
8132           *result = sr;
8133         }
8134     }
8135
8136   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8137
8138   return FALSE;
8139 }
8140
8141 /**
8142  * clutter_actor_get_preferred_width:
8143  * @self: A #ClutterActor
8144  * @for_height: available height when computing the preferred width,
8145  *   or a negative value to indicate that no height is defined
8146  * @min_width_p: (out) (allow-none): return location for minimum width,
8147  *   or %NULL
8148  * @natural_width_p: (out) (allow-none): return location for the natural
8149  *   width, or %NULL
8150  *
8151  * Computes the requested minimum and natural widths for an actor,
8152  * optionally depending on the specified height, or if they are
8153  * already computed, returns the cached values.
8154  *
8155  * An actor may not get its request - depending on the layout
8156  * manager that's in effect.
8157  *
8158  * A request should not incorporate the actor's scale or anchor point;
8159  * those transformations do not affect layout, only rendering.
8160  *
8161  * Since: 0.8
8162  */
8163 void
8164 clutter_actor_get_preferred_width (ClutterActor *self,
8165                                    gfloat        for_height,
8166                                    gfloat       *min_width_p,
8167                                    gfloat       *natural_width_p)
8168 {
8169   float request_min_width, request_natural_width;
8170   SizeRequest *cached_size_request;
8171   const ClutterLayoutInfo *info;
8172   ClutterActorPrivate *priv;
8173   gboolean found_in_cache;
8174
8175   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8176
8177   priv = self->priv;
8178
8179   info = _clutter_actor_get_layout_info_or_defaults (self);
8180
8181   /* we shortcircuit the case of a fixed size set using set_width() */
8182   if (priv->min_width_set && priv->natural_width_set)
8183     {
8184       if (min_width_p != NULL)
8185         *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8186
8187       if (natural_width_p != NULL)
8188         *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8189
8190       return;
8191     }
8192
8193   /* the remaining cases are:
8194    *
8195    *   - either min_width or natural_width have been set
8196    *   - neither min_width or natural_width have been set
8197    *
8198    * in both cases, we go through the cache (and through the actor in case
8199    * of cache misses) and determine the authoritative value depending on
8200    * the *_set flags.
8201    */
8202
8203   if (!priv->needs_width_request)
8204     {
8205       found_in_cache =
8206         _clutter_actor_get_cached_size_request (for_height,
8207                                                 priv->width_requests,
8208                                                 &cached_size_request);
8209     }
8210   else
8211     {
8212       /* if the actor needs a width request we use the first slot */
8213       found_in_cache = FALSE;
8214       cached_size_request = &priv->width_requests[0];
8215     }
8216
8217   if (!found_in_cache)
8218     {
8219       gfloat minimum_width, natural_width;
8220       ClutterActorClass *klass;
8221
8222       minimum_width = natural_width = 0;
8223
8224       /* adjust for the margin */
8225       if (for_height >= 0)
8226         {
8227           for_height -= (info->margin.top + info->margin.bottom);
8228           if (for_height < 0)
8229             for_height = 0;
8230         }
8231
8232       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8233
8234       klass = CLUTTER_ACTOR_GET_CLASS (self);
8235       klass->get_preferred_width (self, for_height,
8236                                   &minimum_width,
8237                                   &natural_width);
8238
8239       /* adjust for the margin */
8240       minimum_width += (info->margin.left + info->margin.right);
8241       natural_width += (info->margin.left + info->margin.right);
8242
8243       /* Due to accumulated float errors, it's better not to warn
8244        * on this, but just fix it.
8245        */
8246       if (natural_width < minimum_width)
8247         natural_width = minimum_width;
8248
8249       cached_size_request->min_size = minimum_width;
8250       cached_size_request->natural_size = natural_width;
8251       cached_size_request->for_size = for_height;
8252       cached_size_request->age = priv->cached_width_age;
8253
8254       priv->cached_width_age += 1;
8255       priv->needs_width_request = FALSE;
8256     }
8257
8258   if (!priv->min_width_set)
8259     request_min_width = cached_size_request->min_size;
8260   else
8261     request_min_width = info->minimum.width;
8262
8263   if (!priv->natural_width_set)
8264     request_natural_width = cached_size_request->natural_size;
8265   else
8266     request_natural_width = info->natural.width;
8267
8268   if (min_width_p)
8269     *min_width_p = request_min_width;
8270
8271   if (natural_width_p)
8272     *natural_width_p = request_natural_width;
8273 }
8274
8275 /**
8276  * clutter_actor_get_preferred_height:
8277  * @self: A #ClutterActor
8278  * @for_width: available width to assume in computing desired height,
8279  *   or a negative value to indicate that no width is defined
8280  * @min_height_p: (out) (allow-none): return location for minimum height,
8281  *   or %NULL
8282  * @natural_height_p: (out) (allow-none): return location for natural
8283  *   height, or %NULL
8284  *
8285  * Computes the requested minimum and natural heights for an actor,
8286  * or if they are already computed, returns the cached values.
8287  *
8288  * An actor may not get its request - depending on the layout
8289  * manager that's in effect.
8290  *
8291  * A request should not incorporate the actor's scale or anchor point;
8292  * those transformations do not affect layout, only rendering.
8293  *
8294  * Since: 0.8
8295  */
8296 void
8297 clutter_actor_get_preferred_height (ClutterActor *self,
8298                                     gfloat        for_width,
8299                                     gfloat       *min_height_p,
8300                                     gfloat       *natural_height_p)
8301 {
8302   float request_min_height, request_natural_height;
8303   SizeRequest *cached_size_request;
8304   const ClutterLayoutInfo *info;
8305   ClutterActorPrivate *priv;
8306   gboolean found_in_cache;
8307
8308   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8309
8310   priv = self->priv;
8311
8312   info = _clutter_actor_get_layout_info_or_defaults (self);
8313
8314   /* we shortcircuit the case of a fixed size set using set_height() */
8315   if (priv->min_height_set && priv->natural_height_set)
8316     {
8317       if (min_height_p != NULL)
8318         *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8319
8320       if (natural_height_p != NULL)
8321         *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8322
8323       return;
8324     }
8325
8326   /* the remaining cases are:
8327    *
8328    *   - either min_height or natural_height have been set
8329    *   - neither min_height or natural_height have been set
8330    *
8331    * in both cases, we go through the cache (and through the actor in case
8332    * of cache misses) and determine the authoritative value depending on
8333    * the *_set flags.
8334    */
8335
8336   if (!priv->needs_height_request)
8337     {
8338       found_in_cache =
8339         _clutter_actor_get_cached_size_request (for_width,
8340                                                 priv->height_requests,
8341                                                 &cached_size_request);
8342     }
8343   else
8344     {
8345       found_in_cache = FALSE;
8346       cached_size_request = &priv->height_requests[0];
8347     }
8348
8349   if (!found_in_cache)
8350     {
8351       gfloat minimum_height, natural_height;
8352       ClutterActorClass *klass;
8353
8354       minimum_height = natural_height = 0;
8355
8356       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8357
8358       /* adjust for margin */
8359       if (for_width >= 0)
8360         {
8361           for_width -= (info->margin.left + info->margin.right);
8362           if (for_width < 0)
8363             for_width = 0;
8364         }
8365
8366       klass = CLUTTER_ACTOR_GET_CLASS (self);
8367       klass->get_preferred_height (self, for_width,
8368                                    &minimum_height,
8369                                    &natural_height);
8370
8371       /* adjust for margin */
8372       minimum_height += (info->margin.top + info->margin.bottom);
8373       natural_height += (info->margin.top + info->margin.bottom);
8374
8375       /* Due to accumulated float errors, it's better not to warn
8376        * on this, but just fix it.
8377        */
8378       if (natural_height < minimum_height)
8379         natural_height = minimum_height;
8380
8381       cached_size_request->min_size = minimum_height;
8382       cached_size_request->natural_size = natural_height;
8383       cached_size_request->for_size = for_width;
8384       cached_size_request->age = priv->cached_height_age;
8385
8386       priv->cached_height_age += 1;
8387       priv->needs_height_request = FALSE;
8388     }
8389
8390   if (!priv->min_height_set)
8391     request_min_height = cached_size_request->min_size;
8392   else
8393     request_min_height = info->minimum.height;
8394
8395   if (!priv->natural_height_set)
8396     request_natural_height = cached_size_request->natural_size;
8397   else
8398     request_natural_height = info->natural.height;
8399
8400   if (min_height_p)
8401     *min_height_p = request_min_height;
8402
8403   if (natural_height_p)
8404     *natural_height_p = request_natural_height;
8405 }
8406
8407 /**
8408  * clutter_actor_get_allocation_box:
8409  * @self: A #ClutterActor
8410  * @box: (out): the function fills this in with the actor's allocation
8411  *
8412  * Gets the layout box an actor has been assigned. The allocation can
8413  * only be assumed valid inside a paint() method; anywhere else, it
8414  * may be out-of-date.
8415  *
8416  * An allocation does not incorporate the actor's scale or anchor point;
8417  * those transformations do not affect layout, only rendering.
8418  *
8419  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8420  * of functions inside the implementation of the get_preferred_width()
8421  * or get_preferred_height() virtual functions.</note>
8422  *
8423  * Since: 0.8
8424  */
8425 void
8426 clutter_actor_get_allocation_box (ClutterActor    *self,
8427                                   ClutterActorBox *box)
8428 {
8429   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8430
8431   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8432    * which limits calling get_allocation to inside paint() basically; or
8433    * we can 2) force a layout, which could be expensive if someone calls
8434    * get_allocation somewhere silly; or we can 3) just return the latest
8435    * value, allowing it to be out-of-date, and assume people know what
8436    * they are doing.
8437    *
8438    * The least-surprises approach that keeps existing code working is
8439    * likely to be 2). People can end up doing some inefficient things,
8440    * though, and in general code that requires 2) is probably broken.
8441    */
8442
8443   /* this implements 2) */
8444   if (G_UNLIKELY (self->priv->needs_allocation))
8445     {
8446       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8447
8448       /* do not queue a relayout on an unparented actor */
8449       if (stage)
8450         _clutter_stage_maybe_relayout (stage);
8451     }
8452
8453   /* commenting out the code above and just keeping this assigment
8454    * implements 3)
8455    */
8456   *box = self->priv->allocation;
8457 }
8458
8459 /**
8460  * clutter_actor_get_allocation_geometry:
8461  * @self: A #ClutterActor
8462  * @geom: (out): allocation geometry in pixels
8463  *
8464  * Gets the layout box an actor has been assigned.  The allocation can
8465  * only be assumed valid inside a paint() method; anywhere else, it
8466  * may be out-of-date.
8467  *
8468  * An allocation does not incorporate the actor's scale or anchor point;
8469  * those transformations do not affect layout, only rendering.
8470  *
8471  * The returned rectangle is in pixels.
8472  *
8473  * Since: 0.8
8474  */
8475 void
8476 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8477                                        ClutterGeometry *geom)
8478 {
8479   ClutterActorBox box;
8480
8481   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8482   g_return_if_fail (geom != NULL);
8483
8484   clutter_actor_get_allocation_box (self, &box);
8485
8486   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8487   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8488   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8489   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8490 }
8491
8492 static void
8493 clutter_actor_update_constraints (ClutterActor    *self,
8494                                   ClutterActorBox *allocation)
8495 {
8496   ClutterActorPrivate *priv = self->priv;
8497   const GList *constraints, *l;
8498
8499   if (priv->constraints == NULL)
8500     return;
8501
8502   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8503   for (l = constraints; l != NULL; l = l->next)
8504     {
8505       ClutterConstraint *constraint = l->data;
8506       ClutterActorMeta *meta = l->data;
8507
8508       if (clutter_actor_meta_get_enabled (meta))
8509         {
8510           _clutter_constraint_update_allocation (constraint,
8511                                                  self,
8512                                                  allocation);
8513
8514           CLUTTER_NOTE (LAYOUT,
8515                         "Allocation of '%s' after constraint '%s': "
8516                         "{ %.2f, %.2f, %.2f, %.2f }",
8517                         _clutter_actor_get_debug_name (self),
8518                         _clutter_actor_meta_get_debug_name (meta),
8519                         allocation->x1,
8520                         allocation->y1,
8521                         allocation->x2,
8522                         allocation->y2);
8523         }
8524     }
8525 }
8526
8527 /*< private >
8528  * clutter_actor_adjust_allocation:
8529  * @self: a #ClutterActor
8530  * @allocation: (inout): the allocation to adjust
8531  *
8532  * Adjusts the passed allocation box taking into account the actor's
8533  * layout information, like alignment, expansion, and margin.
8534  */
8535 static void
8536 clutter_actor_adjust_allocation (ClutterActor    *self,
8537                                  ClutterActorBox *allocation)
8538 {
8539   ClutterActorBox adj_allocation;
8540   float alloc_width, alloc_height;
8541   float min_width, min_height;
8542   float nat_width, nat_height;
8543   ClutterRequestMode req_mode;
8544
8545   adj_allocation = *allocation;
8546
8547   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8548
8549   /* we want to hit the cache, so we use the public API */
8550   req_mode = clutter_actor_get_request_mode (self);
8551
8552   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8553     {
8554       clutter_actor_get_preferred_width (self, -1,
8555                                          &min_width,
8556                                          &nat_width);
8557       clutter_actor_get_preferred_height (self, alloc_width,
8558                                           &min_height,
8559                                           &nat_height);
8560     }
8561   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8562     {
8563       clutter_actor_get_preferred_height (self, -1,
8564                                           &min_height,
8565                                           &nat_height);
8566       clutter_actor_get_preferred_height (self, alloc_height,
8567                                           &min_width,
8568                                           &nat_width);
8569     }
8570
8571 #ifdef CLUTTER_ENABLE_DEBUG
8572   /* warn about underallocations */
8573   if (_clutter_diagnostic_enabled () &&
8574       (floorf (min_width - alloc_width) > 0 ||
8575        floorf (min_height - alloc_height) > 0))
8576     {
8577       ClutterActor *parent = clutter_actor_get_parent (self);
8578
8579       /* the only actors that are allowed to be underallocated are the Stage,
8580        * as it doesn't have an implicit size, and Actors that specifically
8581        * told us that they want to opt-out from layout control mechanisms
8582        * through the NO_LAYOUT escape hatch.
8583        */
8584       if (parent != NULL &&
8585           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8586         {
8587           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8588                      "of %.2f x %.2f from its parent actor '%s', but its "
8589                      "requested minimum size is of %.2f x %.2f",
8590                      _clutter_actor_get_debug_name (self),
8591                      alloc_width, alloc_height,
8592                      _clutter_actor_get_debug_name (parent),
8593                      min_width, min_height);
8594         }
8595     }
8596 #endif
8597
8598   clutter_actor_adjust_width (self,
8599                               &min_width,
8600                               &nat_width,
8601                               &adj_allocation.x1,
8602                               &adj_allocation.x2);
8603
8604   clutter_actor_adjust_height (self,
8605                                &min_height,
8606                                &nat_height,
8607                                &adj_allocation.y1,
8608                                &adj_allocation.y2);
8609
8610   /* we maintain the invariant that an allocation cannot be adjusted
8611    * to be outside the parent-given box
8612    */
8613   if (adj_allocation.x1 < allocation->x1 ||
8614       adj_allocation.y1 < allocation->y1 ||
8615       adj_allocation.x2 > allocation->x2 ||
8616       adj_allocation.y2 > allocation->y2)
8617     {
8618       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8619                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8620                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8621                  _clutter_actor_get_debug_name (self),
8622                  adj_allocation.x1, adj_allocation.y1,
8623                  adj_allocation.x2 - adj_allocation.x1,
8624                  adj_allocation.y2 - adj_allocation.y1,
8625                  allocation->x1, allocation->y1,
8626                  allocation->x2 - allocation->x1,
8627                  allocation->y2 - allocation->y1);
8628       return;
8629     }
8630
8631   *allocation = adj_allocation;
8632 }
8633
8634 /**
8635  * clutter_actor_allocate:
8636  * @self: A #ClutterActor
8637  * @box: new allocation of the actor, in parent-relative coordinates
8638  * @flags: flags that control the allocation
8639  *
8640  * Called by the parent of an actor to assign the actor its size.
8641  * Should never be called by applications (except when implementing
8642  * a container or layout manager).
8643  *
8644  * Actors can know from their allocation box whether they have moved
8645  * with respect to their parent actor. The @flags parameter describes
8646  * additional information about the allocation, for instance whether
8647  * the parent has moved with respect to the stage, for example because
8648  * a grandparent's origin has moved.
8649  *
8650  * Since: 0.8
8651  */
8652 void
8653 clutter_actor_allocate (ClutterActor           *self,
8654                         const ClutterActorBox  *box,
8655                         ClutterAllocationFlags  flags)
8656 {
8657   ClutterActorPrivate *priv;
8658   ClutterActorClass *klass;
8659   ClutterActorBox old_allocation, real_allocation;
8660   gboolean origin_changed, child_moved, size_changed;
8661   gboolean stage_allocation_changed;
8662
8663   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8664   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8665     {
8666       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8667                  "which isn't a descendent of the stage!\n",
8668                  self, _clutter_actor_get_debug_name (self));
8669       return;
8670     }
8671
8672   priv = self->priv;
8673
8674   old_allocation = priv->allocation;
8675   real_allocation = *box;
8676
8677   /* constraints are allowed to modify the allocation only here; we do
8678    * this prior to all the other checks so that we can bail out if the
8679    * allocation did not change
8680    */
8681   clutter_actor_update_constraints (self, &real_allocation);
8682
8683   /* adjust the allocation depending on the align/margin properties */
8684   clutter_actor_adjust_allocation (self, &real_allocation);
8685
8686   if (real_allocation.x2 < real_allocation.x1 ||
8687       real_allocation.y2 < real_allocation.y1)
8688     {
8689       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8690                  _clutter_actor_get_debug_name (self),
8691                  real_allocation.x2 - real_allocation.x1,
8692                  real_allocation.y2 - real_allocation.y1);
8693     }
8694
8695   /* we allow 0-sized actors, but not negative-sized ones */
8696   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8697   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8698
8699   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8700
8701   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8702                  real_allocation.y1 != old_allocation.y1);
8703
8704   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8705                   real_allocation.y2 != old_allocation.y2);
8706
8707   if (origin_changed || child_moved || size_changed)
8708     stage_allocation_changed = TRUE;
8709   else
8710     stage_allocation_changed = FALSE;
8711
8712   /* If we get an allocation "out of the blue"
8713    * (we did not queue relayout), then we want to
8714    * ignore it. But if we have needs_allocation set,
8715    * we want to guarantee that allocate() virtual
8716    * method is always called, i.e. that queue_relayout()
8717    * always results in an allocate() invocation on
8718    * an actor.
8719    *
8720    * The optimization here is to avoid re-allocating
8721    * actors that did not queue relayout and were
8722    * not moved.
8723    */
8724   if (!priv->needs_allocation && !stage_allocation_changed)
8725     {
8726       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8727       return;
8728     }
8729
8730   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8731    * clutter_actor_allocate(), it indicates whether the parent has its
8732    * absolute origin moved; when passed in to ClutterActor::allocate()
8733    * virtual method though, it indicates whether the child has its
8734    * absolute origin moved.  So we set it when child_moved is TRUE
8735    */
8736   if (child_moved)
8737     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8738
8739   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8740
8741   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8742                 _clutter_actor_get_debug_name (self));
8743
8744   klass = CLUTTER_ACTOR_GET_CLASS (self);
8745   klass->allocate (self, &real_allocation, flags);
8746
8747   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8748
8749   if (stage_allocation_changed)
8750     clutter_actor_queue_redraw (self);
8751 }
8752
8753 /**
8754  * clutter_actor_set_allocation:
8755  * @self: a #ClutterActor
8756  * @box: a #ClutterActorBox
8757  * @flags: allocation flags
8758  *
8759  * Stores the allocation of @self as defined by @box.
8760  *
8761  * This function can only be called from within the implementation of
8762  * the #ClutterActorClass.allocate() virtual function.
8763  *
8764  * The allocation should have been adjusted to take into account constraints,
8765  * alignment, and margin properties. If you are implementing a #ClutterActor
8766  * subclass that provides its own layout management policy for its children
8767  * instead of using a #ClutterLayoutManager delegate, you should not call
8768  * this function on the children of @self; instead, you should call
8769  * clutter_actor_allocate(), which will adjust the allocation box for
8770  * you.
8771  *
8772  * This function should only be used by subclasses of #ClutterActor
8773  * that wish to store their allocation but cannot chain up to the
8774  * parent's implementation; the default implementation of the
8775  * #ClutterActorClass.allocate() virtual function will call this
8776  * function.
8777  *
8778  * It is important to note that, while chaining up was the recommended
8779  * behaviour for #ClutterActor subclasses prior to the introduction of
8780  * this function, it is recommended to call clutter_actor_set_allocation()
8781  * instead.
8782  *
8783  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8784  * to handle the allocation of its children, this function will call
8785  * the clutter_layout_manager_allocate() function only if the
8786  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8787  * expected that the subclass will call clutter_layout_manager_allocate()
8788  * by itself. For instance, the following code:
8789  *
8790  * |[
8791  * static void
8792  * my_actor_allocate (ClutterActor *actor,
8793  *                    const ClutterActorBox *allocation,
8794  *                    ClutterAllocationFlags flags)
8795  * {
8796  *   ClutterActorBox new_alloc;
8797  *   ClutterAllocationFlags new_flags;
8798  *
8799  *   adjust_allocation (allocation, &amp;new_alloc);
8800  *
8801  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8802  *
8803  *   /&ast; this will use the layout manager set on the actor &ast;/
8804  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8805  * }
8806  * ]|
8807  *
8808  * is equivalent to this:
8809  *
8810  * |[
8811  * static void
8812  * my_actor_allocate (ClutterActor *actor,
8813  *                    const ClutterActorBox *allocation,
8814  *                    ClutterAllocationFlags flags)
8815  * {
8816  *   ClutterLayoutManager *layout;
8817  *   ClutterActorBox new_alloc;
8818  *
8819  *   adjust_allocation (allocation, &amp;new_alloc);
8820  *
8821  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8822  *
8823  *   layout = clutter_actor_get_layout_manager (actor);
8824  *   clutter_layout_manager_allocate (layout,
8825  *                                    CLUTTER_CONTAINER (actor),
8826  *                                    &amp;new_alloc,
8827  *                                    flags);
8828  * }
8829  * ]|
8830  *
8831  * Since: 1.10
8832  */
8833 void
8834 clutter_actor_set_allocation (ClutterActor           *self,
8835                               const ClutterActorBox  *box,
8836                               ClutterAllocationFlags  flags)
8837 {
8838   ClutterActorPrivate *priv;
8839   gboolean changed;
8840
8841   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8842   g_return_if_fail (box != NULL);
8843
8844   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8845     {
8846       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8847                   "can only be called from within the implementation of "
8848                   "the ClutterActor::allocate() virtual function.");
8849       return;
8850     }
8851
8852   priv = self->priv;
8853
8854   g_object_freeze_notify (G_OBJECT (self));
8855
8856   changed = clutter_actor_set_allocation_internal (self, box, flags);
8857
8858   /* we allocate our children before we notify changes in our geometry,
8859    * so that people connecting to properties will be able to get valid
8860    * data out of the sub-tree of the scene graph that has this actor at
8861    * the root.
8862    */
8863   clutter_actor_maybe_layout_children (self, box, flags);
8864
8865   if (changed)
8866     {
8867       ClutterActorBox signal_box = priv->allocation;
8868       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8869
8870       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8871                      &signal_box,
8872                      signal_flags);
8873     }
8874
8875   g_object_thaw_notify (G_OBJECT (self));
8876 }
8877
8878 /**
8879  * clutter_actor_set_geometry:
8880  * @self: A #ClutterActor
8881  * @geometry: A #ClutterGeometry
8882  *
8883  * Sets the actor's fixed position and forces its minimum and natural
8884  * size, in pixels. This means the untransformed actor will have the
8885  * given geometry. This is the same as calling clutter_actor_set_position()
8886  * and clutter_actor_set_size().
8887  *
8888  * Deprecated: 1.10: Use clutter_actor_set_position() and
8889  *   clutter_actor_set_size() instead.
8890  */
8891 void
8892 clutter_actor_set_geometry (ClutterActor          *self,
8893                             const ClutterGeometry *geometry)
8894 {
8895   g_object_freeze_notify (G_OBJECT (self));
8896
8897   clutter_actor_set_position (self, geometry->x, geometry->y);
8898   clutter_actor_set_size (self, geometry->width, geometry->height);
8899
8900   g_object_thaw_notify (G_OBJECT (self));
8901 }
8902
8903 /**
8904  * clutter_actor_get_geometry:
8905  * @self: A #ClutterActor
8906  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8907  *
8908  * Gets the size and position of an actor relative to its parent
8909  * actor. This is the same as calling clutter_actor_get_position() and
8910  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8911  * requested size and position if the actor's allocation is invalid.
8912  *
8913  * Deprecated: 1.10: Use clutter_actor_get_position() and
8914  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8915  *   instead.
8916  */
8917 void
8918 clutter_actor_get_geometry (ClutterActor    *self,
8919                             ClutterGeometry *geometry)
8920 {
8921   gfloat x, y, width, height;
8922
8923   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8924   g_return_if_fail (geometry != NULL);
8925
8926   clutter_actor_get_position (self, &x, &y);
8927   clutter_actor_get_size (self, &width, &height);
8928
8929   geometry->x = (int) x;
8930   geometry->y = (int) y;
8931   geometry->width = (int) width;
8932   geometry->height = (int) height;
8933 }
8934
8935 /**
8936  * clutter_actor_set_position:
8937  * @self: A #ClutterActor
8938  * @x: New left position of actor in pixels.
8939  * @y: New top position of actor in pixels.
8940  *
8941  * Sets the actor's fixed position in pixels relative to any parent
8942  * actor.
8943  *
8944  * If a layout manager is in use, this position will override the
8945  * layout manager and force a fixed position.
8946  */
8947 void
8948 clutter_actor_set_position (ClutterActor *self,
8949                             gfloat        x,
8950                             gfloat        y)
8951 {
8952   ClutterPoint new_position;
8953
8954   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8955
8956   clutter_point_init (&new_position, x, y);
8957
8958   if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
8959     {
8960       ClutterPoint cur_position;
8961
8962       cur_position.x = clutter_actor_get_x (self);
8963       cur_position.y = clutter_actor_get_y (self);
8964
8965       _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
8966                                         &cur_position,
8967                                         &new_position);
8968     }
8969   else
8970     _clutter_actor_update_transition (self,
8971                                       obj_props[PROP_POSITION],
8972                                       &new_position);
8973
8974   clutter_actor_queue_relayout (self);
8975 }
8976
8977 /**
8978  * clutter_actor_get_fixed_position_set:
8979  * @self: A #ClutterActor
8980  *
8981  * Checks whether an actor has a fixed position set (and will thus be
8982  * unaffected by any layout manager).
8983  *
8984  * Return value: %TRUE if the fixed position is set on the actor
8985  *
8986  * Since: 0.8
8987  */
8988 gboolean
8989 clutter_actor_get_fixed_position_set (ClutterActor *self)
8990 {
8991   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8992
8993   return self->priv->position_set;
8994 }
8995
8996 /**
8997  * clutter_actor_set_fixed_position_set:
8998  * @self: A #ClutterActor
8999  * @is_set: whether to use fixed position
9000  *
9001  * Sets whether an actor has a fixed position set (and will thus be
9002  * unaffected by any layout manager).
9003  *
9004  * Since: 0.8
9005  */
9006 void
9007 clutter_actor_set_fixed_position_set (ClutterActor *self,
9008                                       gboolean      is_set)
9009 {
9010   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9011
9012   if (self->priv->position_set == (is_set != FALSE))
9013     return;
9014
9015   self->priv->position_set = is_set != FALSE;
9016   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
9017
9018   clutter_actor_queue_relayout (self);
9019 }
9020
9021 /**
9022  * clutter_actor_move_by:
9023  * @self: A #ClutterActor
9024  * @dx: Distance to move Actor on X axis.
9025  * @dy: Distance to move Actor on Y axis.
9026  *
9027  * Moves an actor by the specified distance relative to its current
9028  * position in pixels.
9029  *
9030  * This function modifies the fixed position of an actor and thus removes
9031  * it from any layout management. Another way to move an actor is with an
9032  * anchor point, see clutter_actor_set_anchor_point().
9033  *
9034  * Since: 0.2
9035  */
9036 void
9037 clutter_actor_move_by (ClutterActor *self,
9038                        gfloat        dx,
9039                        gfloat        dy)
9040 {
9041   const ClutterLayoutInfo *info;
9042   gfloat x, y;
9043
9044   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9045
9046   info = _clutter_actor_get_layout_info_or_defaults (self);
9047   x = info->fixed_pos.x;
9048   y = info->fixed_pos.y;
9049
9050   clutter_actor_set_position (self, x + dx, y + dy);
9051 }
9052
9053 static void
9054 clutter_actor_set_min_width (ClutterActor *self,
9055                              gfloat        min_width)
9056 {
9057   ClutterActorPrivate *priv = self->priv;
9058   ClutterActorBox old = { 0, };
9059   ClutterLayoutInfo *info;
9060
9061   /* if we are setting the size on a top-level actor and the
9062    * backend only supports static top-levels (e.g. framebuffers)
9063    * then we ignore the passed value and we override it with
9064    * the stage implementation's preferred size.
9065    */
9066   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9067       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9068     return;
9069
9070   info = _clutter_actor_get_layout_info (self);
9071
9072   if (priv->min_width_set && min_width == info->minimum.width)
9073     return;
9074
9075   g_object_freeze_notify (G_OBJECT (self));
9076
9077   clutter_actor_store_old_geometry (self, &old);
9078
9079   info->minimum.width = min_width;
9080   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
9081   clutter_actor_set_min_width_set (self, TRUE);
9082
9083   clutter_actor_notify_if_geometry_changed (self, &old);
9084
9085   g_object_thaw_notify (G_OBJECT (self));
9086
9087   clutter_actor_queue_relayout (self);
9088 }
9089
9090 static void
9091 clutter_actor_set_min_height (ClutterActor *self,
9092                               gfloat        min_height)
9093
9094 {
9095   ClutterActorPrivate *priv = self->priv;
9096   ClutterActorBox old = { 0, };
9097   ClutterLayoutInfo *info;
9098
9099   /* if we are setting the size on a top-level actor and the
9100    * backend only supports static top-levels (e.g. framebuffers)
9101    * then we ignore the passed value and we override it with
9102    * the stage implementation's preferred size.
9103    */
9104   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9105       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9106     return;
9107
9108   info = _clutter_actor_get_layout_info (self);
9109
9110   if (priv->min_height_set && min_height == info->minimum.height)
9111     return;
9112
9113   g_object_freeze_notify (G_OBJECT (self));
9114
9115   clutter_actor_store_old_geometry (self, &old);
9116
9117   info->minimum.height = min_height;
9118   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
9119   clutter_actor_set_min_height_set (self, TRUE);
9120
9121   clutter_actor_notify_if_geometry_changed (self, &old);
9122
9123   g_object_thaw_notify (G_OBJECT (self));
9124
9125   clutter_actor_queue_relayout (self);
9126 }
9127
9128 static void
9129 clutter_actor_set_natural_width (ClutterActor *self,
9130                                  gfloat        natural_width)
9131 {
9132   ClutterActorPrivate *priv = self->priv;
9133   ClutterActorBox old = { 0, };
9134   ClutterLayoutInfo *info;
9135
9136   /* if we are setting the size on a top-level actor and the
9137    * backend only supports static top-levels (e.g. framebuffers)
9138    * then we ignore the passed value and we override it with
9139    * the stage implementation's preferred size.
9140    */
9141   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9142       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9143     return;
9144
9145   info = _clutter_actor_get_layout_info (self);
9146
9147   if (priv->natural_width_set && natural_width == info->natural.width)
9148     return;
9149
9150   g_object_freeze_notify (G_OBJECT (self));
9151
9152   clutter_actor_store_old_geometry (self, &old);
9153
9154   info->natural.width = natural_width;
9155   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9156   clutter_actor_set_natural_width_set (self, TRUE);
9157
9158   clutter_actor_notify_if_geometry_changed (self, &old);
9159
9160   g_object_thaw_notify (G_OBJECT (self));
9161
9162   clutter_actor_queue_relayout (self);
9163 }
9164
9165 static void
9166 clutter_actor_set_natural_height (ClutterActor *self,
9167                                   gfloat        natural_height)
9168 {
9169   ClutterActorPrivate *priv = self->priv;
9170   ClutterActorBox old = { 0, };
9171   ClutterLayoutInfo *info;
9172
9173   /* if we are setting the size on a top-level actor and the
9174    * backend only supports static top-levels (e.g. framebuffers)
9175    * then we ignore the passed value and we override it with
9176    * the stage implementation's preferred size.
9177    */
9178   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9179       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9180     return;
9181
9182   info = _clutter_actor_get_layout_info (self);
9183
9184   if (priv->natural_height_set && natural_height == info->natural.height)
9185     return;
9186
9187   g_object_freeze_notify (G_OBJECT (self));
9188
9189   clutter_actor_store_old_geometry (self, &old);
9190
9191   info->natural.height = natural_height;
9192   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9193   clutter_actor_set_natural_height_set (self, TRUE);
9194
9195   clutter_actor_notify_if_geometry_changed (self, &old);
9196
9197   g_object_thaw_notify (G_OBJECT (self));
9198
9199   clutter_actor_queue_relayout (self);
9200 }
9201
9202 static void
9203 clutter_actor_set_min_width_set (ClutterActor *self,
9204                                  gboolean      use_min_width)
9205 {
9206   ClutterActorPrivate *priv = self->priv;
9207   ClutterActorBox old = { 0, };
9208
9209   if (priv->min_width_set == (use_min_width != FALSE))
9210     return;
9211
9212   clutter_actor_store_old_geometry (self, &old);
9213
9214   priv->min_width_set = use_min_width != FALSE;
9215   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9216
9217   clutter_actor_notify_if_geometry_changed (self, &old);
9218
9219   clutter_actor_queue_relayout (self);
9220 }
9221
9222 static void
9223 clutter_actor_set_min_height_set (ClutterActor *self,
9224                                   gboolean      use_min_height)
9225 {
9226   ClutterActorPrivate *priv = self->priv;
9227   ClutterActorBox old = { 0, };
9228
9229   if (priv->min_height_set == (use_min_height != FALSE))
9230     return;
9231
9232   clutter_actor_store_old_geometry (self, &old);
9233
9234   priv->min_height_set = use_min_height != FALSE;
9235   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9236
9237   clutter_actor_notify_if_geometry_changed (self, &old);
9238
9239   clutter_actor_queue_relayout (self);
9240 }
9241
9242 static void
9243 clutter_actor_set_natural_width_set (ClutterActor *self,
9244                                      gboolean      use_natural_width)
9245 {
9246   ClutterActorPrivate *priv = self->priv;
9247   ClutterActorBox old = { 0, };
9248
9249   if (priv->natural_width_set == (use_natural_width != FALSE))
9250     return;
9251
9252   clutter_actor_store_old_geometry (self, &old);
9253
9254   priv->natural_width_set = use_natural_width != FALSE;
9255   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9256
9257   clutter_actor_notify_if_geometry_changed (self, &old);
9258
9259   clutter_actor_queue_relayout (self);
9260 }
9261
9262 static void
9263 clutter_actor_set_natural_height_set (ClutterActor *self,
9264                                       gboolean      use_natural_height)
9265 {
9266   ClutterActorPrivate *priv = self->priv;
9267   ClutterActorBox old = { 0, };
9268
9269   if (priv->natural_height_set == (use_natural_height != FALSE))
9270     return;
9271
9272   clutter_actor_store_old_geometry (self, &old);
9273
9274   priv->natural_height_set = use_natural_height != FALSE;
9275   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9276
9277   clutter_actor_notify_if_geometry_changed (self, &old);
9278
9279   clutter_actor_queue_relayout (self);
9280 }
9281
9282 /**
9283  * clutter_actor_set_request_mode:
9284  * @self: a #ClutterActor
9285  * @mode: the request mode
9286  *
9287  * Sets the geometry request mode of @self.
9288  *
9289  * The @mode determines the order for invoking
9290  * clutter_actor_get_preferred_width() and
9291  * clutter_actor_get_preferred_height()
9292  *
9293  * Since: 1.2
9294  */
9295 void
9296 clutter_actor_set_request_mode (ClutterActor       *self,
9297                                 ClutterRequestMode  mode)
9298 {
9299   ClutterActorPrivate *priv;
9300
9301   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9302
9303   priv = self->priv;
9304
9305   if (priv->request_mode == mode)
9306     return;
9307
9308   priv->request_mode = mode;
9309
9310   priv->needs_width_request = TRUE;
9311   priv->needs_height_request = TRUE;
9312
9313   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9314
9315   clutter_actor_queue_relayout (self);
9316 }
9317
9318 /**
9319  * clutter_actor_get_request_mode:
9320  * @self: a #ClutterActor
9321  *
9322  * Retrieves the geometry request mode of @self
9323  *
9324  * Return value: the request mode for the actor
9325  *
9326  * Since: 1.2
9327  */
9328 ClutterRequestMode
9329 clutter_actor_get_request_mode (ClutterActor *self)
9330 {
9331   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9332                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9333
9334   return self->priv->request_mode;
9335 }
9336
9337 /* variant of set_width() without checks and without notification
9338  * freeze+thaw, for internal usage only
9339  */
9340 static inline void
9341 clutter_actor_set_width_internal (ClutterActor *self,
9342                                   gfloat        width)
9343 {
9344   if (width >= 0)
9345     {
9346       /* the Stage will use the :min-width to control the minimum
9347        * width to be resized to, so we should not be setting it
9348        * along with the :natural-width
9349        */
9350       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9351         clutter_actor_set_min_width (self, width);
9352
9353       clutter_actor_set_natural_width (self, width);
9354     }
9355   else
9356     {
9357       /* we only unset the :natural-width for the Stage */
9358       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9359         clutter_actor_set_min_width_set (self, FALSE);
9360
9361       clutter_actor_set_natural_width_set (self, FALSE);
9362     }
9363 }
9364
9365 /* variant of set_height() without checks and without notification
9366  * freeze+thaw, for internal usage only
9367  */
9368 static inline void
9369 clutter_actor_set_height_internal (ClutterActor *self,
9370                                    gfloat        height)
9371 {
9372   if (height >= 0)
9373     {
9374       /* see the comment above in set_width_internal() */
9375       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9376         clutter_actor_set_min_height (self, height);
9377
9378       clutter_actor_set_natural_height (self, height);
9379     }
9380   else
9381     {
9382       /* see the comment above in set_width_internal() */
9383       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9384         clutter_actor_set_min_height_set (self, FALSE);
9385
9386       clutter_actor_set_natural_height_set (self, FALSE);
9387     }
9388 }
9389
9390 static void
9391 clutter_actor_set_size_internal (ClutterActor      *self,
9392                                  const ClutterSize *size)
9393 {
9394   if (size != NULL)
9395     {
9396       clutter_actor_set_width_internal (self, size->width);
9397       clutter_actor_set_height_internal (self, size->height);
9398     }
9399   else
9400     {
9401       clutter_actor_set_width_internal (self, -1);
9402       clutter_actor_set_height_internal (self, -1);
9403     }
9404 }
9405
9406 /**
9407  * clutter_actor_set_size:
9408  * @self: A #ClutterActor
9409  * @width: New width of actor in pixels, or -1
9410  * @height: New height of actor in pixels, or -1
9411  *
9412  * Sets the actor's size request in pixels. This overrides any
9413  * "normal" size request the actor would have. For example
9414  * a text actor might normally request the size of the text;
9415  * this function would force a specific size instead.
9416  *
9417  * If @width and/or @height are -1 the actor will use its
9418  * "normal" size request instead of overriding it, i.e.
9419  * you can "unset" the size with -1.
9420  *
9421  * This function sets or unsets both the minimum and natural size.
9422  */
9423 void
9424 clutter_actor_set_size (ClutterActor *self,
9425                         gfloat        width,
9426                         gfloat        height)
9427 {
9428   ClutterSize new_size;
9429
9430   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9431
9432   clutter_size_init (&new_size, width, height);
9433
9434   if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9435     {
9436       /* minor optimization: if we don't have a duration then we can
9437        * skip the get_size() below, to avoid the chance of going through
9438        * get_preferred_width() and get_preferred_height() just to jump to
9439        * a new desired size
9440        */
9441       if (clutter_actor_get_easing_duration (self) == 0)
9442         {
9443           g_object_freeze_notify (G_OBJECT (self));
9444
9445           clutter_actor_set_size_internal (self, &new_size);
9446
9447           g_object_thaw_notify (G_OBJECT (self));
9448
9449           return;
9450         }
9451       else
9452         {
9453           ClutterSize cur_size;
9454
9455           clutter_size_init (&cur_size,
9456                              clutter_actor_get_width (self),
9457                              clutter_actor_get_height (self));
9458
9459          _clutter_actor_create_transition (self,
9460                                            obj_props[PROP_SIZE],
9461                                            &cur_size,
9462                                            &new_size);
9463         }
9464     }
9465   else
9466     _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9467
9468   clutter_actor_queue_relayout (self);
9469 }
9470
9471 /**
9472  * clutter_actor_get_size:
9473  * @self: A #ClutterActor
9474  * @width: (out) (allow-none): return location for the width, or %NULL.
9475  * @height: (out) (allow-none): return location for the height, or %NULL.
9476  *
9477  * This function tries to "do what you mean" and return
9478  * the size an actor will have. If the actor has a valid
9479  * allocation, the allocation will be returned; otherwise,
9480  * the actors natural size request will be returned.
9481  *
9482  * If you care whether you get the request vs. the allocation, you
9483  * should probably call a different function like
9484  * clutter_actor_get_allocation_box() or
9485  * clutter_actor_get_preferred_width().
9486  *
9487  * Since: 0.2
9488  */
9489 void
9490 clutter_actor_get_size (ClutterActor *self,
9491                         gfloat       *width,
9492                         gfloat       *height)
9493 {
9494   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9495
9496   if (width)
9497     *width = clutter_actor_get_width (self);
9498
9499   if (height)
9500     *height = clutter_actor_get_height (self);
9501 }
9502
9503 /**
9504  * clutter_actor_get_position:
9505  * @self: a #ClutterActor
9506  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9507  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9508  *
9509  * This function tries to "do what you mean" and tell you where the
9510  * actor is, prior to any transformations. Retrieves the fixed
9511  * position of an actor in pixels, if one has been set; otherwise, if
9512  * the allocation is valid, returns the actor's allocated position;
9513  * otherwise, returns 0,0.
9514  *
9515  * The returned position is in pixels.
9516  *
9517  * Since: 0.6
9518  */
9519 void
9520 clutter_actor_get_position (ClutterActor *self,
9521                             gfloat       *x,
9522                             gfloat       *y)
9523 {
9524   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9525
9526   if (x)
9527     *x = clutter_actor_get_x (self);
9528
9529   if (y)
9530     *y = clutter_actor_get_y (self);
9531 }
9532
9533 /**
9534  * clutter_actor_get_transformed_position:
9535  * @self: A #ClutterActor
9536  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9537  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9538  *
9539  * Gets the absolute position of an actor, in pixels relative to the stage.
9540  *
9541  * Since: 0.8
9542  */
9543 void
9544 clutter_actor_get_transformed_position (ClutterActor *self,
9545                                         gfloat       *x,
9546                                         gfloat       *y)
9547 {
9548   ClutterVertex v1;
9549   ClutterVertex v2;
9550
9551   v1.x = v1.y = v1.z = 0;
9552   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9553
9554   if (x)
9555     *x = v2.x;
9556
9557   if (y)
9558     *y = v2.y;
9559 }
9560
9561 /**
9562  * clutter_actor_get_transformed_size:
9563  * @self: A #ClutterActor
9564  * @width: (out) (allow-none): return location for the width, or %NULL
9565  * @height: (out) (allow-none): return location for the height, or %NULL
9566  *
9567  * Gets the absolute size of an actor in pixels, taking into account the
9568  * scaling factors.
9569  *
9570  * If the actor has a valid allocation, the allocated size will be used.
9571  * If the actor has not a valid allocation then the preferred size will
9572  * be transformed and returned.
9573  *
9574  * If you want the transformed allocation, see
9575  * clutter_actor_get_abs_allocation_vertices() instead.
9576  *
9577  * <note>When the actor (or one of its ancestors) is rotated around the
9578  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9579  * as a generic quadrangle; in that case this function returns the size
9580  * of the smallest rectangle that encapsulates the entire quad. Please
9581  * note that in this case no assumptions can be made about the relative
9582  * position of this envelope to the absolute position of the actor, as
9583  * returned by clutter_actor_get_transformed_position(); if you need this
9584  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9585  * to get the coords of the actual quadrangle.</note>
9586  *
9587  * Since: 0.8
9588  */
9589 void
9590 clutter_actor_get_transformed_size (ClutterActor *self,
9591                                     gfloat       *width,
9592                                     gfloat       *height)
9593 {
9594   ClutterActorPrivate *priv;
9595   ClutterVertex v[4];
9596   gfloat x_min, x_max, y_min, y_max;
9597   gint i;
9598
9599   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9600
9601   priv = self->priv;
9602
9603   /* if the actor hasn't been allocated yet, get the preferred
9604    * size and transform that
9605    */
9606   if (priv->needs_allocation)
9607     {
9608       gfloat natural_width, natural_height;
9609       ClutterActorBox box;
9610
9611       /* Make a fake allocation to transform.
9612        *
9613        * NB: _clutter_actor_transform_and_project_box expects a box in
9614        * the actor's coordinate space... */
9615
9616       box.x1 = 0;
9617       box.y1 = 0;
9618
9619       natural_width = natural_height = 0;
9620       clutter_actor_get_preferred_size (self, NULL, NULL,
9621                                         &natural_width,
9622                                         &natural_height);
9623
9624       box.x2 = natural_width;
9625       box.y2 = natural_height;
9626
9627       _clutter_actor_transform_and_project_box (self, &box, v);
9628     }
9629   else
9630     clutter_actor_get_abs_allocation_vertices (self, v);
9631
9632   x_min = x_max = v[0].x;
9633   y_min = y_max = v[0].y;
9634
9635   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9636     {
9637       if (v[i].x < x_min)
9638         x_min = v[i].x;
9639
9640       if (v[i].x > x_max)
9641         x_max = v[i].x;
9642
9643       if (v[i].y < y_min)
9644         y_min = v[i].y;
9645
9646       if (v[i].y > y_max)
9647         y_max = v[i].y;
9648     }
9649
9650   if (width)
9651     *width  = x_max - x_min;
9652
9653   if (height)
9654     *height = y_max - y_min;
9655 }
9656
9657 /**
9658  * clutter_actor_get_width:
9659  * @self: A #ClutterActor
9660  *
9661  * Retrieves the width of a #ClutterActor.
9662  *
9663  * If the actor has a valid allocation, this function will return the
9664  * width of the allocated area given to the actor.
9665  *
9666  * If the actor does not have a valid allocation, this function will
9667  * return the actor's natural width, that is the preferred width of
9668  * the actor.
9669  *
9670  * If you care whether you get the preferred width or the width that
9671  * has been assigned to the actor, you should probably call a different
9672  * function like clutter_actor_get_allocation_box() to retrieve the
9673  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9674  * preferred width.
9675  *
9676  * If an actor has a fixed width, for instance a width that has been
9677  * assigned using clutter_actor_set_width(), the width returned will
9678  * be the same value.
9679  *
9680  * Return value: the width of the actor, in pixels
9681  */
9682 gfloat
9683 clutter_actor_get_width (ClutterActor *self)
9684 {
9685   ClutterActorPrivate *priv;
9686
9687   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9688
9689   priv = self->priv;
9690
9691   if (priv->needs_allocation)
9692     {
9693       gfloat natural_width = 0;
9694
9695       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9696         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9697       else
9698         {
9699           gfloat natural_height = 0;
9700
9701           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9702           clutter_actor_get_preferred_width (self, natural_height,
9703                                              NULL,
9704                                              &natural_width);
9705         }
9706
9707       return natural_width;
9708     }
9709   else
9710     return priv->allocation.x2 - priv->allocation.x1;
9711 }
9712
9713 /**
9714  * clutter_actor_get_height:
9715  * @self: A #ClutterActor
9716  *
9717  * Retrieves the height of a #ClutterActor.
9718  *
9719  * If the actor has a valid allocation, this function will return the
9720  * height of the allocated area given to the actor.
9721  *
9722  * If the actor does not have a valid allocation, this function will
9723  * return the actor's natural height, that is the preferred height of
9724  * the actor.
9725  *
9726  * If you care whether you get the preferred height or the height that
9727  * has been assigned to the actor, you should probably call a different
9728  * function like clutter_actor_get_allocation_box() to retrieve the
9729  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9730  * preferred height.
9731  *
9732  * If an actor has a fixed height, for instance a height that has been
9733  * assigned using clutter_actor_set_height(), the height returned will
9734  * be the same value.
9735  *
9736  * Return value: the height of the actor, in pixels
9737  */
9738 gfloat
9739 clutter_actor_get_height (ClutterActor *self)
9740 {
9741   ClutterActorPrivate *priv;
9742
9743   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9744
9745   priv = self->priv;
9746
9747   if (priv->needs_allocation)
9748     {
9749       gfloat natural_height = 0;
9750
9751       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9752         {
9753           gfloat natural_width = 0;
9754
9755           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9756           clutter_actor_get_preferred_height (self, natural_width,
9757                                               NULL, &natural_height);
9758         }
9759       else
9760         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9761
9762       return natural_height;
9763     }
9764   else
9765     return priv->allocation.y2 - priv->allocation.y1;
9766 }
9767
9768 /**
9769  * clutter_actor_set_width:
9770  * @self: A #ClutterActor
9771  * @width: Requested new width for the actor, in pixels, or -1
9772  *
9773  * Forces a width on an actor, causing the actor's preferred width
9774  * and height (if any) to be ignored.
9775  *
9776  * If @width is -1 the actor will use its preferred width request
9777  * instead of overriding it, i.e. you can "unset" the width with -1.
9778  *
9779  * This function sets both the minimum and natural size of the actor.
9780  *
9781  * since: 0.2
9782  */
9783 void
9784 clutter_actor_set_width (ClutterActor *self,
9785                          gfloat        width)
9786 {
9787   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9788
9789   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9790     {
9791       float cur_size;
9792
9793       /* minor optimization: if we don't have a duration
9794        * then we can skip the get_width() below, to avoid
9795        * the chance of going through get_preferred_width()
9796        * just to jump to a new desired width.
9797        */
9798       if (clutter_actor_get_easing_duration (self) == 0)
9799         {
9800           g_object_freeze_notify (G_OBJECT (self));
9801
9802           clutter_actor_set_width_internal (self, width);
9803
9804           g_object_thaw_notify (G_OBJECT (self));
9805
9806           return;
9807         }
9808       else
9809         cur_size = clutter_actor_get_width (self);
9810
9811       _clutter_actor_create_transition (self,
9812                                         obj_props[PROP_WIDTH],
9813                                         cur_size,
9814                                         width);
9815     }
9816   else
9817     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9818 }
9819
9820 /**
9821  * clutter_actor_set_height:
9822  * @self: A #ClutterActor
9823  * @height: Requested new height for the actor, in pixels, or -1
9824  *
9825  * Forces a height on an actor, causing the actor's preferred width
9826  * and height (if any) to be ignored.
9827  *
9828  * If @height is -1 the actor will use its preferred height instead of
9829  * overriding it, i.e. you can "unset" the height with -1.
9830  *
9831  * This function sets both the minimum and natural size of the actor.
9832  *
9833  * since: 0.2
9834  */
9835 void
9836 clutter_actor_set_height (ClutterActor *self,
9837                           gfloat        height)
9838 {
9839   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9840
9841   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9842     {
9843       float cur_size;
9844
9845       /* see the comment in clutter_actor_set_width() above */
9846       if (clutter_actor_get_easing_duration (self) == 0)
9847         {
9848           g_object_freeze_notify (G_OBJECT (self));
9849
9850           clutter_actor_set_height_internal (self, height);
9851
9852           g_object_thaw_notify (G_OBJECT (self));
9853
9854           return;
9855         }
9856       else
9857         cur_size = clutter_actor_get_height (self);
9858
9859       _clutter_actor_create_transition (self,
9860                                         obj_props[PROP_HEIGHT],
9861                                         cur_size,
9862                                         height);
9863     }
9864   else
9865     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9866 }
9867
9868 static inline void
9869 clutter_actor_set_x_internal (ClutterActor *self,
9870                               float         x)
9871 {
9872   ClutterActorPrivate *priv = self->priv;
9873   ClutterLayoutInfo *linfo;
9874   ClutterActorBox old = { 0, };
9875
9876   linfo = _clutter_actor_get_layout_info (self);
9877
9878   if (priv->position_set && linfo->fixed_pos.x == x)
9879     return;
9880
9881   clutter_actor_store_old_geometry (self, &old);
9882
9883   linfo->fixed_pos.x = x;
9884   clutter_actor_set_fixed_position_set (self, TRUE);
9885
9886   clutter_actor_notify_if_geometry_changed (self, &old);
9887
9888   clutter_actor_queue_relayout (self);
9889 }
9890
9891 static inline void
9892 clutter_actor_set_y_internal (ClutterActor *self,
9893                               float         y)
9894 {
9895   ClutterActorPrivate *priv = self->priv;
9896   ClutterLayoutInfo *linfo;
9897   ClutterActorBox old = { 0, };
9898
9899   linfo = _clutter_actor_get_layout_info (self);
9900
9901   if (priv->position_set && linfo->fixed_pos.y == y)
9902     return;
9903
9904   clutter_actor_store_old_geometry (self, &old);
9905
9906   linfo->fixed_pos.y = y;
9907   clutter_actor_set_fixed_position_set (self, TRUE);
9908
9909   clutter_actor_notify_if_geometry_changed (self, &old);
9910
9911   clutter_actor_queue_relayout (self);
9912 }
9913
9914 static void
9915 clutter_actor_set_position_internal (ClutterActor       *self,
9916                                      const ClutterPoint *position)
9917 {
9918   ClutterActorPrivate *priv = self->priv;
9919   ClutterLayoutInfo *linfo;
9920   ClutterActorBox old = { 0, };
9921
9922   linfo = _clutter_actor_get_layout_info (self);
9923
9924   if (priv->position_set &&
9925       clutter_point_equals (position, &linfo->fixed_pos))
9926     return;
9927
9928   clutter_actor_store_old_geometry (self, &old);
9929
9930   if (position != NULL)
9931     {
9932       linfo->fixed_pos = *position;
9933       clutter_actor_set_fixed_position_set (self, TRUE);
9934     }
9935   else
9936     clutter_actor_set_fixed_position_set (self, FALSE);
9937
9938   clutter_actor_notify_if_geometry_changed (self, &old);
9939
9940   clutter_actor_queue_relayout (self);
9941 }
9942
9943 /**
9944  * clutter_actor_set_x:
9945  * @self: a #ClutterActor
9946  * @x: the actor's position on the X axis
9947  *
9948  * Sets the actor's X coordinate, relative to its parent, in pixels.
9949  *
9950  * Overrides any layout manager and forces a fixed position for
9951  * the actor.
9952  *
9953  * The #ClutterActor:x property is animatable.
9954  *
9955  * Since: 0.6
9956  */
9957 void
9958 clutter_actor_set_x (ClutterActor *self,
9959                      gfloat        x)
9960 {
9961   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9962
9963   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9964     {
9965       float cur_position = clutter_actor_get_x (self);
9966
9967       _clutter_actor_create_transition (self, obj_props[PROP_X],
9968                                         cur_position,
9969                                         x);
9970     }
9971   else
9972     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9973 }
9974
9975 /**
9976  * clutter_actor_set_y:
9977  * @self: a #ClutterActor
9978  * @y: the actor's position on the Y axis
9979  *
9980  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9981  *
9982  * Overrides any layout manager and forces a fixed position for
9983  * the actor.
9984  *
9985  * The #ClutterActor:y property is animatable.
9986  *
9987  * Since: 0.6
9988  */
9989 void
9990 clutter_actor_set_y (ClutterActor *self,
9991                      gfloat        y)
9992 {
9993   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9994
9995   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9996     {
9997       float cur_position = clutter_actor_get_y (self);
9998
9999       _clutter_actor_create_transition (self, obj_props[PROP_Y],
10000                                         cur_position,
10001                                         y);
10002     }
10003   else
10004     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
10005 }
10006
10007 /**
10008  * clutter_actor_get_x:
10009  * @self: A #ClutterActor
10010  *
10011  * Retrieves the X coordinate of a #ClutterActor.
10012  *
10013  * This function tries to "do what you mean", by returning the
10014  * correct value depending on the actor's state.
10015  *
10016  * If the actor has a valid allocation, this function will return
10017  * the X coordinate of the origin of the allocation box.
10018  *
10019  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
10020  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10021  * function will return that coordinate.
10022  *
10023  * If both the allocation and a fixed position are missing, this function
10024  * will return 0.
10025  *
10026  * Return value: the X coordinate, in pixels, ignoring any
10027  *   transformation (i.e. scaling, rotation)
10028  */
10029 gfloat
10030 clutter_actor_get_x (ClutterActor *self)
10031 {
10032   ClutterActorPrivate *priv;
10033
10034   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10035
10036   priv = self->priv;
10037
10038   if (priv->needs_allocation)
10039     {
10040       if (priv->position_set)
10041         {
10042           const ClutterLayoutInfo *info;
10043
10044           info = _clutter_actor_get_layout_info_or_defaults (self);
10045
10046           return info->fixed_pos.x;
10047         }
10048       else
10049         return 0;
10050     }
10051   else
10052     return priv->allocation.x1;
10053 }
10054
10055 /**
10056  * clutter_actor_get_y:
10057  * @self: A #ClutterActor
10058  *
10059  * Retrieves the Y coordinate of a #ClutterActor.
10060  *
10061  * This function tries to "do what you mean", by returning the
10062  * correct value depending on the actor's state.
10063  *
10064  * If the actor has a valid allocation, this function will return
10065  * the Y coordinate of the origin of the allocation box.
10066  *
10067  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
10068  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10069  * function will return that coordinate.
10070  *
10071  * If both the allocation and a fixed position are missing, this function
10072  * will return 0.
10073  *
10074  * Return value: the Y coordinate, in pixels, ignoring any
10075  *   transformation (i.e. scaling, rotation)
10076  */
10077 gfloat
10078 clutter_actor_get_y (ClutterActor *self)
10079 {
10080   ClutterActorPrivate *priv;
10081
10082   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10083
10084   priv = self->priv;
10085
10086   if (priv->needs_allocation)
10087     {
10088       if (priv->position_set)
10089         {
10090           const ClutterLayoutInfo *info;
10091
10092           info = _clutter_actor_get_layout_info_or_defaults (self);
10093
10094           return info->fixed_pos.y;
10095         }
10096       else
10097         return 0;
10098     }
10099   else
10100     return priv->allocation.y1;
10101 }
10102
10103 /**
10104  * clutter_actor_set_scale:
10105  * @self: A #ClutterActor
10106  * @scale_x: double factor to scale actor by horizontally.
10107  * @scale_y: double factor to scale actor by vertically.
10108  *
10109  * Scales an actor with the given factors. The scaling is relative to
10110  * the scale center and the anchor point. The scale center is
10111  * unchanged by this function and defaults to 0,0.
10112  *
10113  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10114  * animatable.
10115  *
10116  * Since: 0.2
10117  */
10118 void
10119 clutter_actor_set_scale (ClutterActor *self,
10120                          gdouble       scale_x,
10121                          gdouble       scale_y)
10122 {
10123   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10124
10125   g_object_freeze_notify (G_OBJECT (self));
10126
10127   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10128   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10129
10130   g_object_thaw_notify (G_OBJECT (self));
10131 }
10132
10133 /**
10134  * clutter_actor_set_scale_full:
10135  * @self: A #ClutterActor
10136  * @scale_x: double factor to scale actor by horizontally.
10137  * @scale_y: double factor to scale actor by vertically.
10138  * @center_x: X coordinate of the center of the scale.
10139  * @center_y: Y coordinate of the center of the scale
10140  *
10141  * Scales an actor with the given factors around the given center
10142  * point. The center point is specified in pixels relative to the
10143  * anchor point (usually the top left corner of the actor).
10144  *
10145  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10146  * are animatable.
10147  *
10148  * Since: 1.0
10149  */
10150 void
10151 clutter_actor_set_scale_full (ClutterActor *self,
10152                               gdouble       scale_x,
10153                               gdouble       scale_y,
10154                               gfloat        center_x,
10155                               gfloat        center_y)
10156 {
10157   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10158
10159   g_object_freeze_notify (G_OBJECT (self));
10160
10161   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10162   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10163   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10164   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10165
10166   g_object_thaw_notify (G_OBJECT (self));
10167 }
10168
10169 /**
10170  * clutter_actor_set_scale_with_gravity:
10171  * @self: A #ClutterActor
10172  * @scale_x: double factor to scale actor by horizontally.
10173  * @scale_y: double factor to scale actor by vertically.
10174  * @gravity: the location of the scale center expressed as a compass
10175  * direction.
10176  *
10177  * Scales an actor with the given factors around the given
10178  * center point. The center point is specified as one of the compass
10179  * directions in #ClutterGravity. For example, setting it to north
10180  * will cause the top of the actor to remain unchanged and the rest of
10181  * the actor to expand left, right and downwards.
10182  *
10183  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10184  * animatable.
10185  *
10186  * Since: 1.0
10187  */
10188 void
10189 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
10190                                       gdouble         scale_x,
10191                                       gdouble         scale_y,
10192                                       ClutterGravity  gravity)
10193 {
10194   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10195
10196   g_object_freeze_notify (G_OBJECT (self));
10197
10198   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10199   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10200   clutter_actor_set_scale_gravity (self, gravity);
10201
10202   g_object_thaw_notify (G_OBJECT (self));
10203 }
10204
10205 /**
10206  * clutter_actor_get_scale:
10207  * @self: A #ClutterActor
10208  * @scale_x: (out) (allow-none): Location to store horizonal
10209  *   scale factor, or %NULL.
10210  * @scale_y: (out) (allow-none): Location to store vertical
10211  *   scale factor, or %NULL.
10212  *
10213  * Retrieves an actors scale factors.
10214  *
10215  * Since: 0.2
10216  */
10217 void
10218 clutter_actor_get_scale (ClutterActor *self,
10219                          gdouble      *scale_x,
10220                          gdouble      *scale_y)
10221 {
10222   const ClutterTransformInfo *info;
10223
10224   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10225
10226   info = _clutter_actor_get_transform_info_or_defaults (self);
10227
10228   if (scale_x)
10229     *scale_x = info->scale_x;
10230
10231   if (scale_y)
10232     *scale_y = info->scale_y;
10233 }
10234
10235 /**
10236  * clutter_actor_get_scale_center:
10237  * @self: A #ClutterActor
10238  * @center_x: (out) (allow-none): Location to store the X position
10239  *   of the scale center, or %NULL.
10240  * @center_y: (out) (allow-none): Location to store the Y position
10241  *   of the scale center, or %NULL.
10242  *
10243  * Retrieves the scale center coordinate in pixels relative to the top
10244  * left corner of the actor. If the scale center was specified using a
10245  * #ClutterGravity this will calculate the pixel offset using the
10246  * current size of the actor.
10247  *
10248  * Since: 1.0
10249  */
10250 void
10251 clutter_actor_get_scale_center (ClutterActor *self,
10252                                 gfloat       *center_x,
10253                                 gfloat       *center_y)
10254 {
10255   const ClutterTransformInfo *info;
10256
10257   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10258
10259   info = _clutter_actor_get_transform_info_or_defaults (self);
10260
10261   clutter_anchor_coord_get_units (self, &info->scale_center,
10262                                   center_x,
10263                                   center_y,
10264                                   NULL);
10265 }
10266
10267 /**
10268  * clutter_actor_get_scale_gravity:
10269  * @self: A #ClutterActor
10270  *
10271  * Retrieves the scale center as a compass direction. If the scale
10272  * center was specified in pixels or units this will return
10273  * %CLUTTER_GRAVITY_NONE.
10274  *
10275  * Return value: the scale gravity
10276  *
10277  * Since: 1.0
10278  */
10279 ClutterGravity
10280 clutter_actor_get_scale_gravity (ClutterActor *self)
10281 {
10282   const ClutterTransformInfo *info;
10283
10284   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10285
10286   info = _clutter_actor_get_transform_info_or_defaults (self);
10287
10288   return clutter_anchor_coord_get_gravity (&info->scale_center);
10289 }
10290
10291 static inline void
10292 clutter_actor_set_opacity_internal (ClutterActor *self,
10293                                     guint8        opacity)
10294 {
10295   ClutterActorPrivate *priv = self->priv;
10296
10297   if (priv->opacity != opacity)
10298     {
10299       priv->opacity = opacity;
10300
10301       /* Queue a redraw from the flatten effect so that it can use
10302          its cached image if available instead of having to redraw the
10303          actual actor. If it doesn't end up using the FBO then the
10304          effect is still able to continue the paint anyway. If there
10305          is no flatten effect yet then this is equivalent to queueing
10306          a full redraw */
10307       _clutter_actor_queue_redraw_full (self,
10308                                         0, /* flags */
10309                                         NULL, /* clip */
10310                                         priv->flatten_effect);
10311
10312       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10313     }
10314 }
10315
10316 /**
10317  * clutter_actor_set_opacity:
10318  * @self: A #ClutterActor
10319  * @opacity: New opacity value for the actor.
10320  *
10321  * Sets the actor's opacity, with zero being completely transparent and
10322  * 255 (0xff) being fully opaque.
10323  *
10324  * The #ClutterActor:opacity property is animatable.
10325  */
10326 void
10327 clutter_actor_set_opacity (ClutterActor *self,
10328                            guint8        opacity)
10329 {
10330   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10331
10332   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10333     {
10334       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10335                                         self->priv->opacity,
10336                                         opacity);
10337     }
10338   else
10339     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10340 }
10341
10342 /*
10343  * clutter_actor_get_paint_opacity_internal:
10344  * @self: a #ClutterActor
10345  *
10346  * Retrieves the absolute opacity of the actor, as it appears on the stage
10347  *
10348  * This function does not do type checks
10349  *
10350  * Return value: the absolute opacity of the actor
10351  */
10352 static guint8
10353 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10354 {
10355   ClutterActorPrivate *priv = self->priv;
10356   ClutterActor *parent;
10357
10358   /* override the top-level opacity to always be 255; even in
10359    * case of ClutterStage:use-alpha being TRUE we want the rest
10360    * of the scene to be painted
10361    */
10362   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10363     return 255;
10364
10365   if (priv->opacity_override >= 0)
10366     return priv->opacity_override;
10367
10368   parent = priv->parent;
10369
10370   /* Factor in the actual actors opacity with parents */
10371   if (parent != NULL)
10372     {
10373       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10374
10375       if (opacity != 0xff)
10376         return (opacity * priv->opacity) / 0xff;
10377     }
10378
10379   return priv->opacity;
10380
10381 }
10382
10383 /**
10384  * clutter_actor_get_paint_opacity:
10385  * @self: A #ClutterActor
10386  *
10387  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10388  *
10389  * This function traverses the hierarchy chain and composites the opacity of
10390  * the actor with that of its parents.
10391  *
10392  * This function is intended for subclasses to use in the paint virtual
10393  * function, to paint themselves with the correct opacity.
10394  *
10395  * Return value: The actor opacity value.
10396  *
10397  * Since: 0.8
10398  */
10399 guint8
10400 clutter_actor_get_paint_opacity (ClutterActor *self)
10401 {
10402   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10403
10404   return clutter_actor_get_paint_opacity_internal (self);
10405 }
10406
10407 /**
10408  * clutter_actor_get_opacity:
10409  * @self: a #ClutterActor
10410  *
10411  * Retrieves the opacity value of an actor, as set by
10412  * clutter_actor_set_opacity().
10413  *
10414  * For retrieving the absolute opacity of the actor inside a paint
10415  * virtual function, see clutter_actor_get_paint_opacity().
10416  *
10417  * Return value: the opacity of the actor
10418  */
10419 guint8
10420 clutter_actor_get_opacity (ClutterActor *self)
10421 {
10422   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10423
10424   return self->priv->opacity;
10425 }
10426
10427 /**
10428  * clutter_actor_set_offscreen_redirect:
10429  * @self: A #ClutterActor
10430  * @redirect: New offscreen redirect flags for the actor.
10431  *
10432  * Defines the circumstances where the actor should be redirected into
10433  * an offscreen image. The offscreen image is used to flatten the
10434  * actor into a single image while painting for two main reasons.
10435  * Firstly, when the actor is painted a second time without any of its
10436  * contents changing it can simply repaint the cached image without
10437  * descending further down the actor hierarchy. Secondly, it will make
10438  * the opacity look correct even if there are overlapping primitives
10439  * in the actor.
10440  *
10441  * Caching the actor could in some cases be a performance win and in
10442  * some cases be a performance lose so it is important to determine
10443  * which value is right for an actor before modifying this value. For
10444  * example, there is never any reason to flatten an actor that is just
10445  * a single texture (such as a #ClutterTexture) because it is
10446  * effectively already cached in an image so the offscreen would be
10447  * redundant. Also if the actor contains primitives that are far apart
10448  * with a large transparent area in the middle (such as a large
10449  * CluterGroup with a small actor in the top left and a small actor in
10450  * the bottom right) then the cached image will contain the entire
10451  * image of the large area and the paint will waste time blending all
10452  * of the transparent pixels in the middle.
10453  *
10454  * The default method of implementing opacity on a container simply
10455  * forwards on the opacity to all of the children. If the children are
10456  * overlapping then it will appear as if they are two separate glassy
10457  * objects and there will be a break in the color where they
10458  * overlap. By redirecting to an offscreen buffer it will be as if the
10459  * two opaque objects are combined into one and then made transparent
10460  * which is usually what is expected.
10461  *
10462  * The image below demonstrates the difference between redirecting and
10463  * not. The image shows two Clutter groups, each containing a red and
10464  * a green rectangle which overlap. The opacity on the group is set to
10465  * 128 (which is 50%). When the offscreen redirect is not used, the
10466  * red rectangle can be seen through the blue rectangle as if the two
10467  * rectangles were separately transparent. When the redirect is used
10468  * the group as a whole is transparent instead so the red rectangle is
10469  * not visible where they overlap.
10470  *
10471  * <figure id="offscreen-redirect">
10472  *   <title>Sample of using an offscreen redirect for transparency</title>
10473  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10474  * </figure>
10475  *
10476  * The default value for this property is 0, so we effectively will
10477  * never redirect an actor offscreen by default. This means that there
10478  * are times that transparent actors may look glassy as described
10479  * above. The reason this is the default is because there is a
10480  * performance trade off between quality and performance here. In many
10481  * cases the default form of glassy opacity looks good enough, but if
10482  * it's not you will need to set the
10483  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10484  * redirection for opacity.
10485  *
10486  * Custom actors that don't contain any overlapping primitives are
10487  * recommended to override the has_overlaps() virtual to return %FALSE
10488  * for maximum efficiency.
10489  *
10490  * Since: 1.8
10491  */
10492 void
10493 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10494                                       ClutterOffscreenRedirect redirect)
10495 {
10496   ClutterActorPrivate *priv;
10497
10498   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10499
10500   priv = self->priv;
10501
10502   if (priv->offscreen_redirect != redirect)
10503     {
10504       priv->offscreen_redirect = redirect;
10505
10506       /* Queue a redraw from the effect so that it can use its cached
10507          image if available instead of having to redraw the actual
10508          actor. If it doesn't end up using the FBO then the effect is
10509          still able to continue the paint anyway. If there is no
10510          effect then this is equivalent to queuing a full redraw */
10511       _clutter_actor_queue_redraw_full (self,
10512                                         0, /* flags */
10513                                         NULL, /* clip */
10514                                         priv->flatten_effect);
10515
10516       g_object_notify_by_pspec (G_OBJECT (self),
10517                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10518     }
10519 }
10520
10521 /**
10522  * clutter_actor_get_offscreen_redirect:
10523  * @self: a #ClutterActor
10524  *
10525  * Retrieves whether to redirect the actor to an offscreen buffer, as
10526  * set by clutter_actor_set_offscreen_redirect().
10527  *
10528  * Return value: the value of the offscreen-redirect property of the actor
10529  *
10530  * Since: 1.8
10531  */
10532 ClutterOffscreenRedirect
10533 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10534 {
10535   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10536
10537   return self->priv->offscreen_redirect;
10538 }
10539
10540 /**
10541  * clutter_actor_set_name:
10542  * @self: A #ClutterActor
10543  * @name: Textual tag to apply to actor
10544  *
10545  * Sets the given name to @self. The name can be used to identify
10546  * a #ClutterActor.
10547  */
10548 void
10549 clutter_actor_set_name (ClutterActor *self,
10550                         const gchar  *name)
10551 {
10552   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10553
10554   g_free (self->priv->name);
10555   self->priv->name = g_strdup (name);
10556
10557   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10558 }
10559
10560 /**
10561  * clutter_actor_get_name:
10562  * @self: A #ClutterActor
10563  *
10564  * Retrieves the name of @self.
10565  *
10566  * Return value: the name of the actor, or %NULL. The returned string is
10567  *   owned by the actor and should not be modified or freed.
10568  */
10569 const gchar *
10570 clutter_actor_get_name (ClutterActor *self)
10571 {
10572   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10573
10574   return self->priv->name;
10575 }
10576
10577 /**
10578  * clutter_actor_get_gid:
10579  * @self: A #ClutterActor
10580  *
10581  * Retrieves the unique id for @self.
10582  *
10583  * Return value: Globally unique value for this object instance.
10584  *
10585  * Since: 0.6
10586  *
10587  * Deprecated: 1.8: The id is not used any longer.
10588  */
10589 guint32
10590 clutter_actor_get_gid (ClutterActor *self)
10591 {
10592   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10593
10594   return self->priv->id;
10595 }
10596
10597 static inline void
10598 clutter_actor_set_depth_internal (ClutterActor *self,
10599                                   float         depth)
10600 {
10601   ClutterTransformInfo *info;
10602
10603   info = _clutter_actor_get_transform_info (self);
10604
10605   if (info->depth != depth)
10606     {
10607       /* Sets Z value - XXX 2.0: should we invert? */
10608       info->depth = depth;
10609
10610       self->priv->transform_valid = FALSE;
10611
10612       /* FIXME - remove this crap; sadly, there are still containers
10613        * in Clutter that depend on this utter brain damage
10614        */
10615       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10616
10617       clutter_actor_queue_redraw (self);
10618
10619       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10620     }
10621 }
10622
10623 /**
10624  * clutter_actor_set_depth:
10625  * @self: a #ClutterActor
10626  * @depth: Z co-ord
10627  *
10628  * Sets the Z coordinate of @self to @depth.
10629  *
10630  * The unit used by @depth is dependant on the perspective setup. See
10631  * also clutter_stage_set_perspective().
10632  */
10633 void
10634 clutter_actor_set_depth (ClutterActor *self,
10635                          gfloat        depth)
10636 {
10637   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10638
10639   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10640     {
10641       const ClutterTransformInfo *info;
10642
10643       info = _clutter_actor_get_transform_info_or_defaults (self);
10644
10645       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10646                                         info->depth,
10647                                         depth);
10648     }
10649   else
10650     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10651
10652   clutter_actor_queue_redraw (self);
10653 }
10654
10655 /**
10656  * clutter_actor_get_depth:
10657  * @self: a #ClutterActor
10658  *
10659  * Retrieves the depth of @self.
10660  *
10661  * Return value: the depth of the actor
10662  */
10663 gfloat
10664 clutter_actor_get_depth (ClutterActor *self)
10665 {
10666   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10667
10668   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10669 }
10670
10671 /**
10672  * clutter_actor_set_rotation:
10673  * @self: a #ClutterActor
10674  * @axis: the axis of rotation
10675  * @angle: the angle of rotation
10676  * @x: X coordinate of the rotation center
10677  * @y: Y coordinate of the rotation center
10678  * @z: Z coordinate of the rotation center
10679  *
10680  * Sets the rotation angle of @self around the given axis.
10681  *
10682  * The rotation center coordinates used depend on the value of @axis:
10683  * <itemizedlist>
10684  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10685  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10686  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10687  * </itemizedlist>
10688  *
10689  * The rotation coordinates are relative to the anchor point of the
10690  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10691  * point is set, the upper left corner is assumed as the origin.
10692  *
10693  * Since: 0.8
10694  */
10695 void
10696 clutter_actor_set_rotation (ClutterActor      *self,
10697                             ClutterRotateAxis  axis,
10698                             gdouble            angle,
10699                             gfloat             x,
10700                             gfloat             y,
10701                             gfloat             z)
10702 {
10703   ClutterVertex v;
10704
10705   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10706
10707   v.x = x;
10708   v.y = y;
10709   v.z = z;
10710
10711   g_object_freeze_notify (G_OBJECT (self));
10712
10713   clutter_actor_set_rotation_angle (self, axis, angle);
10714   clutter_actor_set_rotation_center_internal (self, axis, &v);
10715
10716   g_object_thaw_notify (G_OBJECT (self));
10717 }
10718
10719 /**
10720  * clutter_actor_set_z_rotation_from_gravity:
10721  * @self: a #ClutterActor
10722  * @angle: the angle of rotation
10723  * @gravity: the center point of the rotation
10724  *
10725  * Sets the rotation angle of @self around the Z axis using the center
10726  * point specified as a compass point. For example to rotate such that
10727  * the center of the actor remains static you can use
10728  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10729  * will move accordingly.
10730  *
10731  * Since: 1.0
10732  */
10733 void
10734 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10735                                            gdouble         angle,
10736                                            ClutterGravity  gravity)
10737 {
10738   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10739
10740   if (gravity == CLUTTER_GRAVITY_NONE)
10741     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10742   else
10743     {
10744       GObject *obj = G_OBJECT (self);
10745       ClutterTransformInfo *info;
10746
10747       info = _clutter_actor_get_transform_info (self);
10748
10749       g_object_freeze_notify (obj);
10750
10751       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10752
10753       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10754       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10755       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10756
10757       g_object_thaw_notify (obj);
10758     }
10759 }
10760
10761 /**
10762  * clutter_actor_get_rotation:
10763  * @self: a #ClutterActor
10764  * @axis: the axis of rotation
10765  * @x: (out): return value for the X coordinate of the center of rotation
10766  * @y: (out): return value for the Y coordinate of the center of rotation
10767  * @z: (out): return value for the Z coordinate of the center of rotation
10768  *
10769  * Retrieves the angle and center of rotation on the given axis,
10770  * set using clutter_actor_set_rotation().
10771  *
10772  * Return value: the angle of rotation
10773  *
10774  * Since: 0.8
10775  */
10776 gdouble
10777 clutter_actor_get_rotation (ClutterActor      *self,
10778                             ClutterRotateAxis  axis,
10779                             gfloat            *x,
10780                             gfloat            *y,
10781                             gfloat            *z)
10782 {
10783   const ClutterTransformInfo *info;
10784   const AnchorCoord *anchor_coord;
10785   gdouble retval = 0;
10786
10787   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10788
10789   info = _clutter_actor_get_transform_info_or_defaults (self);
10790
10791   switch (axis)
10792     {
10793     case CLUTTER_X_AXIS:
10794       anchor_coord = &info->rx_center;
10795       retval = info->rx_angle;
10796       break;
10797
10798     case CLUTTER_Y_AXIS:
10799       anchor_coord = &info->ry_center;
10800       retval = info->ry_angle;
10801       break;
10802
10803     case CLUTTER_Z_AXIS:
10804       anchor_coord = &info->rz_center;
10805       retval = info->rz_angle;
10806       break;
10807
10808     default:
10809       anchor_coord = NULL;
10810       retval = 0.0;
10811       break;
10812     }
10813
10814   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10815
10816   return retval;
10817 }
10818
10819 /**
10820  * clutter_actor_get_z_rotation_gravity:
10821  * @self: A #ClutterActor
10822  *
10823  * Retrieves the center for the rotation around the Z axis as a
10824  * compass direction. If the center was specified in pixels or units
10825  * this will return %CLUTTER_GRAVITY_NONE.
10826  *
10827  * Return value: the Z rotation center
10828  *
10829  * Since: 1.0
10830  */
10831 ClutterGravity
10832 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10833 {
10834   const ClutterTransformInfo *info;
10835
10836   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10837
10838   info = _clutter_actor_get_transform_info_or_defaults (self);
10839
10840   return clutter_anchor_coord_get_gravity (&info->rz_center);
10841 }
10842
10843 /**
10844  * clutter_actor_set_clip:
10845  * @self: A #ClutterActor
10846  * @xoff: X offset of the clip rectangle
10847  * @yoff: Y offset of the clip rectangle
10848  * @width: Width of the clip rectangle
10849  * @height: Height of the clip rectangle
10850  *
10851  * Sets clip area for @self. The clip area is always computed from the
10852  * upper left corner of the actor, even if the anchor point is set
10853  * otherwise.
10854  *
10855  * Since: 0.6
10856  */
10857 void
10858 clutter_actor_set_clip (ClutterActor *self,
10859                         gfloat        xoff,
10860                         gfloat        yoff,
10861                         gfloat        width,
10862                         gfloat        height)
10863 {
10864   ClutterActorPrivate *priv;
10865
10866   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10867
10868   priv = self->priv;
10869
10870   if (priv->has_clip &&
10871       priv->clip.x == xoff &&
10872       priv->clip.y == yoff &&
10873       priv->clip.width == width &&
10874       priv->clip.height == height)
10875     return;
10876
10877   priv->clip.x = xoff;
10878   priv->clip.y = yoff;
10879   priv->clip.width = width;
10880   priv->clip.height = height;
10881
10882   priv->has_clip = TRUE;
10883
10884   clutter_actor_queue_redraw (self);
10885
10886   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10887   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10888 }
10889
10890 /**
10891  * clutter_actor_remove_clip:
10892  * @self: A #ClutterActor
10893  *
10894  * Removes clip area from @self.
10895  */
10896 void
10897 clutter_actor_remove_clip (ClutterActor *self)
10898 {
10899   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10900
10901   if (!self->priv->has_clip)
10902     return;
10903
10904   self->priv->has_clip = FALSE;
10905
10906   clutter_actor_queue_redraw (self);
10907
10908   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10909 }
10910
10911 /**
10912  * clutter_actor_has_clip:
10913  * @self: a #ClutterActor
10914  *
10915  * Determines whether the actor has a clip area set or not.
10916  *
10917  * Return value: %TRUE if the actor has a clip area set.
10918  *
10919  * Since: 0.1.1
10920  */
10921 gboolean
10922 clutter_actor_has_clip (ClutterActor *self)
10923 {
10924   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10925
10926   return self->priv->has_clip;
10927 }
10928
10929 /**
10930  * clutter_actor_get_clip:
10931  * @self: a #ClutterActor
10932  * @xoff: (out) (allow-none): return location for the X offset of
10933  *   the clip rectangle, or %NULL
10934  * @yoff: (out) (allow-none): return location for the Y offset of
10935  *   the clip rectangle, or %NULL
10936  * @width: (out) (allow-none): return location for the width of
10937  *   the clip rectangle, or %NULL
10938  * @height: (out) (allow-none): return location for the height of
10939  *   the clip rectangle, or %NULL
10940  *
10941  * Gets the clip area for @self, if any is set
10942  *
10943  * Since: 0.6
10944  */
10945 void
10946 clutter_actor_get_clip (ClutterActor *self,
10947                         gfloat       *xoff,
10948                         gfloat       *yoff,
10949                         gfloat       *width,
10950                         gfloat       *height)
10951 {
10952   ClutterActorPrivate *priv;
10953
10954   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10955
10956   priv = self->priv;
10957
10958   if (!priv->has_clip)
10959     return;
10960
10961   if (xoff != NULL)
10962     *xoff = priv->clip.x;
10963
10964   if (yoff != NULL)
10965     *yoff = priv->clip.y;
10966
10967   if (width != NULL)
10968     *width = priv->clip.width;
10969
10970   if (height != NULL)
10971     *height = priv->clip.height;
10972 }
10973
10974 /**
10975  * clutter_actor_get_children:
10976  * @self: a #ClutterActor
10977  *
10978  * Retrieves the list of children of @self.
10979  *
10980  * Return value: (transfer container) (element-type ClutterActor): A newly
10981  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10982  *   done.
10983  *
10984  * Since: 1.10
10985  */
10986 GList *
10987 clutter_actor_get_children (ClutterActor *self)
10988 {
10989   ClutterActor *iter;
10990   GList *res;
10991
10992   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10993
10994   /* we walk the list backward so that we can use prepend(),
10995    * which is O(1)
10996    */
10997   for (iter = self->priv->last_child, res = NULL;
10998        iter != NULL;
10999        iter = iter->priv->prev_sibling)
11000     {
11001       res = g_list_prepend (res, iter);
11002     }
11003
11004   return res;
11005 }
11006
11007 /*< private >
11008  * insert_child_at_depth:
11009  * @self: a #ClutterActor
11010  * @child: a #ClutterActor
11011  *
11012  * Inserts @child inside the list of children held by @self, using
11013  * the depth as the insertion criteria.
11014  *
11015  * This sadly makes the insertion not O(1), but we can keep the
11016  * list sorted so that the painters algorithm we use for painting
11017  * the children will work correctly.
11018  */
11019 static void
11020 insert_child_at_depth (ClutterActor *self,
11021                        ClutterActor *child,
11022                        gpointer      dummy G_GNUC_UNUSED)
11023 {
11024   ClutterActor *iter;
11025   float child_depth;
11026
11027   child->priv->parent = self;
11028
11029   child_depth =
11030     _clutter_actor_get_transform_info_or_defaults (child)->depth;
11031
11032   /* special-case the first child */
11033   if (self->priv->n_children == 0)
11034     {
11035       self->priv->first_child = child;
11036       self->priv->last_child = child;
11037
11038       child->priv->next_sibling = NULL;
11039       child->priv->prev_sibling = NULL;
11040
11041       return;
11042     }
11043
11044   /* Find the right place to insert the child so that it will still be
11045      sorted and the child will be after all of the actors at the same
11046      dept */
11047   for (iter = self->priv->first_child;
11048        iter != NULL;
11049        iter = iter->priv->next_sibling)
11050     {
11051       float iter_depth;
11052
11053       iter_depth =
11054         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
11055
11056       if (iter_depth > child_depth)
11057         break;
11058     }
11059
11060   if (iter != NULL)
11061     {
11062       ClutterActor *tmp = iter->priv->prev_sibling;
11063
11064       if (tmp != NULL)
11065         tmp->priv->next_sibling = child;
11066
11067       /* Insert the node before the found one */
11068       child->priv->prev_sibling = iter->priv->prev_sibling;
11069       child->priv->next_sibling = iter;
11070       iter->priv->prev_sibling = child;
11071     }
11072   else
11073     {
11074       ClutterActor *tmp = self->priv->last_child;
11075
11076       if (tmp != NULL)
11077         tmp->priv->next_sibling = child;
11078
11079       /* insert the node at the end of the list */
11080       child->priv->prev_sibling = self->priv->last_child;
11081       child->priv->next_sibling = NULL;
11082     }
11083
11084   if (child->priv->prev_sibling == NULL)
11085     self->priv->first_child = child;
11086
11087   if (child->priv->next_sibling == NULL)
11088     self->priv->last_child = child;
11089 }
11090
11091 static void
11092 insert_child_at_index (ClutterActor *self,
11093                        ClutterActor *child,
11094                        gpointer      data_)
11095 {
11096   gint index_ = GPOINTER_TO_INT (data_);
11097
11098   child->priv->parent = self;
11099
11100   if (index_ == 0)
11101     {
11102       ClutterActor *tmp = self->priv->first_child;
11103
11104       if (tmp != NULL)
11105         tmp->priv->prev_sibling = child;
11106
11107       child->priv->prev_sibling = NULL;
11108       child->priv->next_sibling = tmp;
11109     }
11110   else if (index_ < 0 || index_ >= self->priv->n_children)
11111     {
11112       ClutterActor *tmp = self->priv->last_child;
11113
11114       if (tmp != NULL)
11115         tmp->priv->next_sibling = child;
11116
11117       child->priv->prev_sibling = tmp;
11118       child->priv->next_sibling = NULL;
11119     }
11120   else
11121     {
11122       ClutterActor *iter;
11123       int i;
11124
11125       for (iter = self->priv->first_child, i = 0;
11126            iter != NULL;
11127            iter = iter->priv->next_sibling, i += 1)
11128         {
11129           if (index_ == i)
11130             {
11131               ClutterActor *tmp = iter->priv->prev_sibling;
11132
11133               child->priv->prev_sibling = tmp;
11134               child->priv->next_sibling = iter;
11135
11136               iter->priv->prev_sibling = child;
11137
11138               if (tmp != NULL)
11139                 tmp->priv->next_sibling = child;
11140
11141               break;
11142             }
11143         }
11144     }
11145
11146   if (child->priv->prev_sibling == NULL)
11147     self->priv->first_child = child;
11148
11149   if (child->priv->next_sibling == NULL)
11150     self->priv->last_child = child;
11151 }
11152
11153 static void
11154 insert_child_above (ClutterActor *self,
11155                     ClutterActor *child,
11156                     gpointer      data)
11157 {
11158   ClutterActor *sibling = data;
11159
11160   child->priv->parent = self;
11161
11162   if (sibling == NULL)
11163     sibling = self->priv->last_child;
11164
11165   child->priv->prev_sibling = sibling;
11166
11167   if (sibling != NULL)
11168     {
11169       ClutterActor *tmp = sibling->priv->next_sibling;
11170
11171       child->priv->next_sibling = tmp;
11172
11173       if (tmp != NULL)
11174         tmp->priv->prev_sibling = child;
11175
11176       sibling->priv->next_sibling = child;
11177     }
11178   else
11179     child->priv->next_sibling = NULL;
11180
11181   if (child->priv->prev_sibling == NULL)
11182     self->priv->first_child = child;
11183
11184   if (child->priv->next_sibling == NULL)
11185     self->priv->last_child = child;
11186 }
11187
11188 static void
11189 insert_child_below (ClutterActor *self,
11190                     ClutterActor *child,
11191                     gpointer      data)
11192 {
11193   ClutterActor *sibling = data;
11194
11195   child->priv->parent = self;
11196
11197   if (sibling == NULL)
11198     sibling = self->priv->first_child;
11199
11200   child->priv->next_sibling = sibling;
11201
11202   if (sibling != NULL)
11203     {
11204       ClutterActor *tmp = sibling->priv->prev_sibling;
11205
11206       child->priv->prev_sibling = tmp;
11207
11208       if (tmp != NULL)
11209         tmp->priv->next_sibling = child;
11210
11211       sibling->priv->prev_sibling = child;
11212     }
11213   else
11214     child->priv->prev_sibling = NULL;
11215
11216   if (child->priv->prev_sibling == NULL)
11217     self->priv->first_child = child;
11218
11219   if (child->priv->next_sibling == NULL)
11220     self->priv->last_child = child;
11221 }
11222
11223 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11224                                            ClutterActor *child,
11225                                            gpointer      data);
11226
11227 typedef enum {
11228   ADD_CHILD_CREATE_META        = 1 << 0,
11229   ADD_CHILD_EMIT_PARENT_SET    = 1 << 1,
11230   ADD_CHILD_EMIT_ACTOR_ADDED   = 1 << 2,
11231   ADD_CHILD_CHECK_STATE        = 1 << 3,
11232   ADD_CHILD_NOTIFY_FIRST_LAST  = 1 << 4,
11233   ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11234
11235   /* default flags for public API */
11236   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
11237                                ADD_CHILD_EMIT_PARENT_SET |
11238                                ADD_CHILD_EMIT_ACTOR_ADDED |
11239                                ADD_CHILD_CHECK_STATE |
11240                                ADD_CHILD_NOTIFY_FIRST_LAST |
11241                                ADD_CHILD_SHOW_ON_SET_PARENT,
11242
11243   /* flags for legacy/deprecated API */
11244   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
11245                                ADD_CHILD_CHECK_STATE |
11246                                ADD_CHILD_NOTIFY_FIRST_LAST |
11247                                ADD_CHILD_SHOW_ON_SET_PARENT
11248 } ClutterActorAddChildFlags;
11249
11250 /*< private >
11251  * clutter_actor_add_child_internal:
11252  * @self: a #ClutterActor
11253  * @child: a #ClutterActor
11254  * @flags: control flags for actions
11255  * @add_func: delegate function
11256  * @data: (closure): data to pass to @add_func
11257  *
11258  * Adds @child to the list of children of @self.
11259  *
11260  * The actual insertion inside the list is delegated to @add_func: this
11261  * function will just set up the state, perform basic checks, and emit
11262  * signals.
11263  *
11264  * The @flags argument is used to perform additional operations.
11265  */
11266 static inline void
11267 clutter_actor_add_child_internal (ClutterActor              *self,
11268                                   ClutterActor              *child,
11269                                   ClutterActorAddChildFlags  flags,
11270                                   ClutterActorAddChildFunc   add_func,
11271                                   gpointer                   data)
11272 {
11273   ClutterTextDirection text_dir;
11274   gboolean create_meta;
11275   gboolean emit_parent_set, emit_actor_added;
11276   gboolean check_state;
11277   gboolean notify_first_last;
11278   gboolean show_on_set_parent;
11279   ClutterActor *old_first_child, *old_last_child;
11280
11281   if (child->priv->parent != NULL)
11282     {
11283       g_warning ("The actor '%s' already has a parent, '%s'. You must "
11284                  "use clutter_actor_remove_child() first.",
11285                  _clutter_actor_get_debug_name (child),
11286                  _clutter_actor_get_debug_name (child->priv->parent));
11287       return;
11288     }
11289
11290   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11291     {
11292       g_warning ("The actor '%s' is a top-level actor, and cannot be "
11293                  "a child of another actor.",
11294                  _clutter_actor_get_debug_name (child));
11295       return;
11296     }
11297
11298 #if 0
11299   /* XXX - this check disallows calling methods that change the stacking
11300    * order within the destruction sequence, by triggering a critical
11301    * warning first, and leaving the actor in an undefined state, which
11302    * then ends up being caught by an assertion.
11303    *
11304    * the reproducible sequence is:
11305    *
11306    *   - actor gets destroyed;
11307    *   - another actor, linked to the first, will try to change the
11308    *     stacking order of the first actor;
11309    *   - changing the stacking order is a composite operation composed
11310    *     by the following steps:
11311    *     1. ref() the child;
11312    *     2. remove_child_internal(), which removes the reference;
11313    *     3. add_child_internal(), which adds a reference;
11314    *   - the state of the actor is not changed between (2) and (3), as
11315    *     it could be an expensive recomputation;
11316    *   - if (3) bails out, then the actor is in an undefined state, but
11317    *     still alive;
11318    *   - the destruction sequence terminates, but the actor is unparented
11319    *     while its state indicates being parented instead.
11320    *   - assertion failure.
11321    *
11322    * the obvious fix would be to decompose each set_child_*_sibling()
11323    * method into proper remove_child()/add_child(), with state validation;
11324    * this may cause excessive work, though, and trigger a cascade of other
11325    * bugs in code that assumes that a change in the stacking order is an
11326    * atomic operation.
11327    *
11328    * another potential fix is to just remove this check here, and let
11329    * code doing stacking order changes inside the destruction sequence
11330    * of an actor continue doing the work.
11331    *
11332    * the third fix is to silently bail out early from every
11333    * set_child_*_sibling() and set_child_at_index() method, and avoid
11334    * doing work.
11335    *
11336    * I have a preference for the second solution, since it involves the
11337    * least amount of work, and the least amount of code duplication.
11338    *
11339    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11340    */
11341   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11342     {
11343       g_warning ("The actor '%s' is currently being destroyed, and "
11344                  "cannot be added as a child of another actor.",
11345                  _clutter_actor_get_debug_name (child));
11346       return;
11347     }
11348 #endif
11349
11350   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11351   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11352   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11353   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11354   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11355   show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11356
11357   old_first_child = self->priv->first_child;
11358   old_last_child = self->priv->last_child;
11359
11360   g_object_freeze_notify (G_OBJECT (self));
11361
11362   if (create_meta)
11363     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11364
11365   g_object_ref_sink (child);
11366   child->priv->parent = NULL;
11367   child->priv->next_sibling = NULL;
11368   child->priv->prev_sibling = NULL;
11369
11370   /* delegate the actual insertion */
11371   add_func (self, child, data);
11372
11373   g_assert (child->priv->parent == self);
11374
11375   self->priv->n_children += 1;
11376
11377   self->priv->age += 1;
11378
11379   /* if push_internal() has been called then we automatically set
11380    * the flag on the actor
11381    */
11382   if (self->priv->internal_child)
11383     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11384
11385   /* children may cause their parent to expand, if they are set
11386    * to expand; if a child is not expanded then it cannot change
11387    * its parent's state. any further change later on will queue
11388    * an expand state check.
11389    *
11390    * this check, with the initial state of the needs_compute_expand
11391    * flag set to FALSE, should avoid recomputing the expand flags
11392    * state while building the actor tree.
11393    */
11394   if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
11395       (child->priv->needs_compute_expand ||
11396        child->priv->needs_x_expand ||
11397        child->priv->needs_y_expand))
11398     {
11399       clutter_actor_queue_compute_expand (self);
11400     }
11401
11402   /* clutter_actor_reparent() will emit ::parent-set for us */
11403   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11404     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11405
11406   if (check_state)
11407     {
11408       /* If parent is mapped or realized, we need to also be mapped or
11409        * realized once we're inside the parent.
11410        */
11411       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11412
11413       /* propagate the parent's text direction to the child */
11414       text_dir = clutter_actor_get_text_direction (self);
11415       clutter_actor_set_text_direction (child, text_dir);
11416     }
11417
11418   if (show_on_set_parent && child->priv->show_on_set_parent)
11419     clutter_actor_show (child);
11420
11421   if (CLUTTER_ACTOR_IS_MAPPED (child))
11422     clutter_actor_queue_redraw (child);
11423
11424   /* maintain the invariant that if an actor needs layout,
11425    * its parents do as well
11426    */
11427   if (child->priv->needs_width_request ||
11428       child->priv->needs_height_request ||
11429       child->priv->needs_allocation)
11430     {
11431       /* we work around the short-circuiting we do
11432        * in clutter_actor_queue_relayout() since we
11433        * want to force a relayout
11434        */
11435       child->priv->needs_width_request = TRUE;
11436       child->priv->needs_height_request = TRUE;
11437       child->priv->needs_allocation = TRUE;
11438
11439       clutter_actor_queue_relayout (child->priv->parent);
11440     }
11441
11442   if (emit_actor_added)
11443     g_signal_emit_by_name (self, "actor-added", child);
11444
11445   if (notify_first_last)
11446     {
11447       if (old_first_child != self->priv->first_child)
11448         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11449
11450       if (old_last_child != self->priv->last_child)
11451         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11452     }
11453
11454   g_object_thaw_notify (G_OBJECT (self));
11455 }
11456
11457 /**
11458  * clutter_actor_add_child:
11459  * @self: a #ClutterActor
11460  * @child: a #ClutterActor
11461  *
11462  * Adds @child to the children of @self.
11463  *
11464  * This function will acquire a reference on @child that will only
11465  * be released when calling clutter_actor_remove_child().
11466  *
11467  * This function will take into consideration the #ClutterActor:depth
11468  * of @child, and will keep the list of children sorted.
11469  *
11470  * This function will emit the #ClutterContainer::actor-added signal
11471  * on @self.
11472  *
11473  * Since: 1.10
11474  */
11475 void
11476 clutter_actor_add_child (ClutterActor *self,
11477                          ClutterActor *child)
11478 {
11479   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11480   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11481   g_return_if_fail (self != child);
11482   g_return_if_fail (child->priv->parent == NULL);
11483
11484   clutter_actor_add_child_internal (self, child,
11485                                     ADD_CHILD_DEFAULT_FLAGS,
11486                                     insert_child_at_depth,
11487                                     NULL);
11488 }
11489
11490 /**
11491  * clutter_actor_insert_child_at_index:
11492  * @self: a #ClutterActor
11493  * @child: a #ClutterActor
11494  * @index_: the index
11495  *
11496  * Inserts @child into the list of children of @self, using the
11497  * given @index_. If @index_ is greater than the number of children
11498  * in @self, or is less than 0, then the new child is added at the end.
11499  *
11500  * This function will acquire a reference on @child that will only
11501  * be released when calling clutter_actor_remove_child().
11502  *
11503  * This function will not take into consideration the #ClutterActor:depth
11504  * of @child.
11505  *
11506  * This function will emit the #ClutterContainer::actor-added signal
11507  * on @self.
11508  *
11509  * Since: 1.10
11510  */
11511 void
11512 clutter_actor_insert_child_at_index (ClutterActor *self,
11513                                      ClutterActor *child,
11514                                      gint          index_)
11515 {
11516   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11517   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11518   g_return_if_fail (self != child);
11519   g_return_if_fail (child->priv->parent == NULL);
11520
11521   clutter_actor_add_child_internal (self, child,
11522                                     ADD_CHILD_DEFAULT_FLAGS,
11523                                     insert_child_at_index,
11524                                     GINT_TO_POINTER (index_));
11525 }
11526
11527 /**
11528  * clutter_actor_insert_child_above:
11529  * @self: a #ClutterActor
11530  * @child: a #ClutterActor
11531  * @sibling: (allow-none): a child of @self, or %NULL
11532  *
11533  * Inserts @child into the list of children of @self, above another
11534  * child of @self or, if @sibling is %NULL, above all the children
11535  * of @self.
11536  *
11537  * This function will acquire a reference on @child that will only
11538  * be released when calling clutter_actor_remove_child().
11539  *
11540  * This function will not take into consideration the #ClutterActor:depth
11541  * of @child.
11542  *
11543  * This function will emit the #ClutterContainer::actor-added signal
11544  * on @self.
11545  *
11546  * Since: 1.10
11547  */
11548 void
11549 clutter_actor_insert_child_above (ClutterActor *self,
11550                                   ClutterActor *child,
11551                                   ClutterActor *sibling)
11552 {
11553   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11554   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11555   g_return_if_fail (self != child);
11556   g_return_if_fail (child != sibling);
11557   g_return_if_fail (child->priv->parent == NULL);
11558   g_return_if_fail (sibling == NULL ||
11559                     (CLUTTER_IS_ACTOR (sibling) &&
11560                      sibling->priv->parent == self));
11561
11562   clutter_actor_add_child_internal (self, child,
11563                                     ADD_CHILD_DEFAULT_FLAGS,
11564                                     insert_child_above,
11565                                     sibling);
11566 }
11567
11568 /**
11569  * clutter_actor_insert_child_below:
11570  * @self: a #ClutterActor
11571  * @child: a #ClutterActor
11572  * @sibling: (allow-none): a child of @self, or %NULL
11573  *
11574  * Inserts @child into the list of children of @self, below another
11575  * child of @self or, if @sibling is %NULL, below all the children
11576  * of @self.
11577  *
11578  * This function will acquire a reference on @child that will only
11579  * be released when calling clutter_actor_remove_child().
11580  *
11581  * This function will not take into consideration the #ClutterActor:depth
11582  * of @child.
11583  *
11584  * This function will emit the #ClutterContainer::actor-added signal
11585  * on @self.
11586  *
11587  * Since: 1.10
11588  */
11589 void
11590 clutter_actor_insert_child_below (ClutterActor *self,
11591                                   ClutterActor *child,
11592                                   ClutterActor *sibling)
11593 {
11594   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11595   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11596   g_return_if_fail (self != child);
11597   g_return_if_fail (child != sibling);
11598   g_return_if_fail (child->priv->parent == NULL);
11599   g_return_if_fail (sibling == NULL ||
11600                     (CLUTTER_IS_ACTOR (sibling) &&
11601                      sibling->priv->parent == self));
11602
11603   clutter_actor_add_child_internal (self, child,
11604                                     ADD_CHILD_DEFAULT_FLAGS,
11605                                     insert_child_below,
11606                                     sibling);
11607 }
11608
11609 /**
11610  * clutter_actor_set_parent:
11611  * @self: A #ClutterActor
11612  * @parent: A new #ClutterActor parent
11613  *
11614  * Sets the parent of @self to @parent.
11615  *
11616  * This function will result in @parent acquiring a reference on @self,
11617  * eventually by sinking its floating reference first. The reference
11618  * will be released by clutter_actor_unparent().
11619  *
11620  * This function should only be called by legacy #ClutterActor<!-- -->s
11621  * implementing the #ClutterContainer interface.
11622  *
11623  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11624  */
11625 void
11626 clutter_actor_set_parent (ClutterActor *self,
11627                           ClutterActor *parent)
11628 {
11629   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11630   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11631   g_return_if_fail (self != parent);
11632   g_return_if_fail (self->priv->parent == NULL);
11633
11634   /* as this function will be called inside ClutterContainer::add
11635    * implementations or when building up a composite actor, we have
11636    * to preserve the old behaviour, and not create child meta or
11637    * emit the ::actor-added signal, to avoid recursion or double
11638    * emissions
11639    */
11640   clutter_actor_add_child_internal (parent, self,
11641                                     ADD_CHILD_LEGACY_FLAGS,
11642                                     insert_child_at_depth,
11643                                     NULL);
11644 }
11645
11646 /**
11647  * clutter_actor_get_parent:
11648  * @self: A #ClutterActor
11649  *
11650  * Retrieves the parent of @self.
11651  *
11652  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11653  *  if no parent is set
11654  */
11655 ClutterActor *
11656 clutter_actor_get_parent (ClutterActor *self)
11657 {
11658   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11659
11660   return self->priv->parent;
11661 }
11662
11663 /**
11664  * clutter_actor_get_paint_visibility:
11665  * @self: A #ClutterActor
11666  *
11667  * Retrieves the 'paint' visibility of an actor recursively checking for non
11668  * visible parents.
11669  *
11670  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11671  *
11672  * Return Value: %TRUE if the actor is visibile and will be painted.
11673  *
11674  * Since: 0.8.4
11675  */
11676 gboolean
11677 clutter_actor_get_paint_visibility (ClutterActor *actor)
11678 {
11679   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11680
11681   return CLUTTER_ACTOR_IS_MAPPED (actor);
11682 }
11683
11684 /**
11685  * clutter_actor_remove_child:
11686  * @self: a #ClutterActor
11687  * @child: a #ClutterActor
11688  *
11689  * Removes @child from the children of @self.
11690  *
11691  * This function will release the reference added by
11692  * clutter_actor_add_child(), so if you want to keep using @child
11693  * you will have to acquire a referenced on it before calling this
11694  * function.
11695  *
11696  * This function will emit the #ClutterContainer::actor-removed
11697  * signal on @self.
11698  *
11699  * Since: 1.10
11700  */
11701 void
11702 clutter_actor_remove_child (ClutterActor *self,
11703                             ClutterActor *child)
11704 {
11705   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11706   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11707   g_return_if_fail (self != child);
11708   g_return_if_fail (child->priv->parent != NULL);
11709   g_return_if_fail (child->priv->parent == self);
11710
11711   clutter_actor_remove_child_internal (self, child,
11712                                        REMOVE_CHILD_DEFAULT_FLAGS);
11713 }
11714
11715 /**
11716  * clutter_actor_remove_all_children:
11717  * @self: a #ClutterActor
11718  *
11719  * Removes all children of @self.
11720  *
11721  * This function releases the reference added by inserting a child actor
11722  * in the list of children of @self.
11723  *
11724  * If the reference count of a child drops to zero, the child will be
11725  * destroyed. If you want to ensure the destruction of all the children
11726  * of @self, use clutter_actor_destroy_all_children().
11727  *
11728  * Since: 1.10
11729  */
11730 void
11731 clutter_actor_remove_all_children (ClutterActor *self)
11732 {
11733   ClutterActorIter iter;
11734
11735   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11736
11737   if (self->priv->n_children == 0)
11738     return;
11739
11740   g_object_freeze_notify (G_OBJECT (self));
11741
11742   clutter_actor_iter_init (&iter, self);
11743   while (clutter_actor_iter_next (&iter, NULL))
11744     clutter_actor_iter_remove (&iter);
11745
11746   g_object_thaw_notify (G_OBJECT (self));
11747
11748   /* sanity check */
11749   g_assert (self->priv->first_child == NULL);
11750   g_assert (self->priv->last_child == NULL);
11751   g_assert (self->priv->n_children == 0);
11752 }
11753
11754 /**
11755  * clutter_actor_destroy_all_children:
11756  * @self: a #ClutterActor
11757  *
11758  * Destroys all children of @self.
11759  *
11760  * This function releases the reference added by inserting a child
11761  * actor in the list of children of @self, and ensures that the
11762  * #ClutterActor::destroy signal is emitted on each child of the
11763  * actor.
11764  *
11765  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11766  * when its reference count drops to 0; the default handler of the
11767  * #ClutterActor::destroy signal will destroy all the children of an
11768  * actor. This function ensures that all children are destroyed, instead
11769  * of just removed from @self, unlike clutter_actor_remove_all_children()
11770  * which will merely release the reference and remove each child.
11771  *
11772  * Unless you acquired an additional reference on each child of @self
11773  * prior to calling clutter_actor_remove_all_children() and want to reuse
11774  * the actors, you should use clutter_actor_destroy_all_children() in
11775  * order to make sure that children are destroyed and signal handlers
11776  * are disconnected even in cases where circular references prevent this
11777  * from automatically happening through reference counting alone.
11778  *
11779  * Since: 1.10
11780  */
11781 void
11782 clutter_actor_destroy_all_children (ClutterActor *self)
11783 {
11784   ClutterActorIter iter;
11785
11786   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11787
11788   if (self->priv->n_children == 0)
11789     return;
11790
11791   g_object_freeze_notify (G_OBJECT (self));
11792
11793   clutter_actor_iter_init (&iter, self);
11794   while (clutter_actor_iter_next (&iter, NULL))
11795     clutter_actor_iter_destroy (&iter);
11796
11797   g_object_thaw_notify (G_OBJECT (self));
11798
11799   /* sanity check */
11800   g_assert (self->priv->first_child == NULL);
11801   g_assert (self->priv->last_child == NULL);
11802   g_assert (self->priv->n_children == 0);
11803 }
11804
11805 typedef struct _InsertBetweenData {
11806   ClutterActor *prev_sibling;
11807   ClutterActor *next_sibling;
11808 } InsertBetweenData;
11809
11810 static void
11811 insert_child_between (ClutterActor *self,
11812                       ClutterActor *child,
11813                       gpointer      data_)
11814 {
11815   InsertBetweenData *data = data_;
11816   ClutterActor *prev_sibling = data->prev_sibling;
11817   ClutterActor *next_sibling = data->next_sibling;
11818
11819   child->priv->parent = self;
11820   child->priv->prev_sibling = prev_sibling;
11821   child->priv->next_sibling = next_sibling;
11822
11823   if (prev_sibling != NULL)
11824     prev_sibling->priv->next_sibling = child;
11825
11826   if (next_sibling != NULL)
11827     next_sibling->priv->prev_sibling = child;
11828
11829   if (child->priv->prev_sibling == NULL)
11830     self->priv->first_child = child;
11831
11832   if (child->priv->next_sibling == NULL)
11833     self->priv->last_child = child;
11834 }
11835
11836 /**
11837  * clutter_actor_replace_child:
11838  * @self: a #ClutterActor
11839  * @old_child: the child of @self to replace
11840  * @new_child: the #ClutterActor to replace @old_child
11841  *
11842  * Replaces @old_child with @new_child in the list of children of @self.
11843  *
11844  * Since: 1.10
11845  */
11846 void
11847 clutter_actor_replace_child (ClutterActor *self,
11848                              ClutterActor *old_child,
11849                              ClutterActor *new_child)
11850 {
11851   ClutterActor *prev_sibling, *next_sibling;
11852   InsertBetweenData clos;
11853
11854   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11855   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11856   g_return_if_fail (old_child->priv->parent == self);
11857   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11858   g_return_if_fail (old_child != new_child);
11859   g_return_if_fail (new_child != self);
11860   g_return_if_fail (new_child->priv->parent == NULL);
11861
11862   prev_sibling = old_child->priv->prev_sibling;
11863   next_sibling = old_child->priv->next_sibling;
11864   clutter_actor_remove_child_internal (self, old_child,
11865                                        REMOVE_CHILD_DEFAULT_FLAGS);
11866
11867   clos.prev_sibling = prev_sibling;
11868   clos.next_sibling = next_sibling;
11869   clutter_actor_add_child_internal (self, new_child,
11870                                     ADD_CHILD_DEFAULT_FLAGS,
11871                                     insert_child_between,
11872                                     &clos);
11873 }
11874
11875 /**
11876  * clutter_actor_unparent:
11877  * @self: a #ClutterActor
11878  *
11879  * Removes the parent of @self.
11880  *
11881  * This will cause the parent of @self to release the reference
11882  * acquired when calling clutter_actor_set_parent(), so if you
11883  * want to keep @self you will have to acquire a reference of
11884  * your own, through g_object_ref().
11885  *
11886  * This function should only be called by legacy #ClutterActor<!-- -->s
11887  * implementing the #ClutterContainer interface.
11888  *
11889  * Since: 0.1.1
11890  *
11891  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11892  */
11893 void
11894 clutter_actor_unparent (ClutterActor *self)
11895 {
11896   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11897
11898   if (self->priv->parent == NULL)
11899     return;
11900
11901   clutter_actor_remove_child_internal (self->priv->parent, self,
11902                                        REMOVE_CHILD_LEGACY_FLAGS);
11903 }
11904
11905 /**
11906  * clutter_actor_reparent:
11907  * @self: a #ClutterActor
11908  * @new_parent: the new #ClutterActor parent
11909  *
11910  * Resets the parent actor of @self.
11911  *
11912  * This function is logically equivalent to calling clutter_actor_unparent()
11913  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11914  * ensures the child is not finalized when unparented, and emits the
11915  * #ClutterActor::parent-set signal only once.
11916  *
11917  * In reality, calling this function is less useful than it sounds, as some
11918  * application code may rely on changes in the intermediate state between
11919  * removal and addition of the actor from its old parent to the @new_parent.
11920  * Thus, it is strongly encouraged to avoid using this function in application
11921  * code.
11922  *
11923  * Since: 0.2
11924  *
11925  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11926  *   clutter_actor_add_child() instead; remember to take a reference on
11927  *   the actor being removed before calling clutter_actor_remove_child()
11928  *   to avoid the reference count dropping to zero and the actor being
11929  *   destroyed.
11930  */
11931 void
11932 clutter_actor_reparent (ClutterActor *self,
11933                         ClutterActor *new_parent)
11934 {
11935   ClutterActorPrivate *priv;
11936
11937   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11938   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11939   g_return_if_fail (self != new_parent);
11940
11941   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11942     {
11943       g_warning ("Cannot set a parent on a toplevel actor");
11944       return;
11945     }
11946
11947   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11948     {
11949       g_warning ("Cannot set a parent currently being destroyed");
11950       return;
11951     }
11952
11953   priv = self->priv;
11954
11955   if (priv->parent != new_parent)
11956     {
11957       ClutterActor *old_parent;
11958
11959       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11960
11961       old_parent = priv->parent;
11962
11963       g_object_ref (self);
11964
11965       if (old_parent != NULL)
11966         {
11967          /* go through the Container implementation if this is a regular
11968           * child and not an internal one
11969           */
11970          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11971            {
11972              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11973
11974              /* this will have to call unparent() */
11975              clutter_container_remove_actor (parent, self);
11976            }
11977          else
11978            clutter_actor_remove_child_internal (old_parent, self,
11979                                                 REMOVE_CHILD_LEGACY_FLAGS);
11980         }
11981
11982       /* Note, will call set_parent() */
11983       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11984         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11985       else
11986         clutter_actor_add_child_internal (new_parent, self,
11987                                           ADD_CHILD_LEGACY_FLAGS,
11988                                           insert_child_at_depth,
11989                                           NULL);
11990
11991       /* we emit the ::parent-set signal once */
11992       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11993
11994       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11995
11996       /* the IN_REPARENT flag suspends state updates */
11997       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11998
11999       g_object_unref (self);
12000    }
12001 }
12002
12003 /**
12004  * clutter_actor_contains:
12005  * @self: A #ClutterActor
12006  * @descendant: A #ClutterActor, possibly contained in @self
12007  *
12008  * Determines if @descendant is contained inside @self (either as an
12009  * immediate child, or as a deeper descendant). If @self and
12010  * @descendant point to the same actor then it will also return %TRUE.
12011  *
12012  * Return value: whether @descendent is contained within @self
12013  *
12014  * Since: 1.4
12015  */
12016 gboolean
12017 clutter_actor_contains (ClutterActor *self,
12018                         ClutterActor *descendant)
12019 {
12020   ClutterActor *actor;
12021
12022   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12023   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
12024
12025   for (actor = descendant; actor; actor = actor->priv->parent)
12026     if (actor == self)
12027       return TRUE;
12028
12029   return FALSE;
12030 }
12031
12032 /**
12033  * clutter_actor_set_child_above_sibling:
12034  * @self: a #ClutterActor
12035  * @child: a #ClutterActor child of @self
12036  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12037  *
12038  * Sets @child to be above @sibling in the list of children of @self.
12039  *
12040  * If @sibling is %NULL, @child will be the new last child of @self.
12041  *
12042  * This function is logically equivalent to removing @child and using
12043  * clutter_actor_insert_child_above(), but it will not emit signals
12044  * or change state on @child.
12045  *
12046  * Since: 1.10
12047  */
12048 void
12049 clutter_actor_set_child_above_sibling (ClutterActor *self,
12050                                        ClutterActor *child,
12051                                        ClutterActor *sibling)
12052 {
12053   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12054   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12055   g_return_if_fail (child->priv->parent == self);
12056   g_return_if_fail (child != sibling);
12057   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12058
12059   if (sibling != NULL)
12060     g_return_if_fail (sibling->priv->parent == self);
12061
12062   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12063       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12064       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12065     return;
12066
12067   /* we don't want to change the state of child, or emit signals, or
12068    * regenerate ChildMeta instances here, but we still want to follow
12069    * the correct sequence of steps encoded in remove_child() and
12070    * add_child(), so that correctness is ensured, and we only go
12071    * through one known code path.
12072    */
12073   g_object_ref (child);
12074   clutter_actor_remove_child_internal (self, child, 0);
12075   clutter_actor_add_child_internal (self, child,
12076                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12077                                     insert_child_above,
12078                                     sibling);
12079
12080   clutter_actor_queue_relayout (self);
12081 }
12082
12083 /**
12084  * clutter_actor_set_child_below_sibling:
12085  * @self: a #ClutterActor
12086  * @child: a #ClutterActor child of @self
12087  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12088  *
12089  * Sets @child to be below @sibling in the list of children of @self.
12090  *
12091  * If @sibling is %NULL, @child will be the new first child of @self.
12092  *
12093  * This function is logically equivalent to removing @self and using
12094  * clutter_actor_insert_child_below(), but it will not emit signals
12095  * or change state on @child.
12096  *
12097  * Since: 1.10
12098  */
12099 void
12100 clutter_actor_set_child_below_sibling (ClutterActor *self,
12101                                        ClutterActor *child,
12102                                        ClutterActor *sibling)
12103 {
12104   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12105   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12106   g_return_if_fail (child->priv->parent == self);
12107   g_return_if_fail (child != sibling);
12108   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12109
12110   if (sibling != NULL)
12111     g_return_if_fail (sibling->priv->parent == self);
12112
12113   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12114       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12115       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12116     return;
12117
12118   /* see the comment in set_child_above_sibling() */
12119   g_object_ref (child);
12120   clutter_actor_remove_child_internal (self, child, 0);
12121   clutter_actor_add_child_internal (self, child,
12122                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12123                                     insert_child_below,
12124                                     sibling);
12125
12126   clutter_actor_queue_relayout (self);
12127 }
12128
12129 /**
12130  * clutter_actor_set_child_at_index:
12131  * @self: a #ClutterActor
12132  * @child: a #ClutterActor child of @self
12133  * @index_: the new index for @child
12134  *
12135  * Changes the index of @child in the list of children of @self.
12136  *
12137  * This function is logically equivalent to removing @child and
12138  * calling clutter_actor_insert_child_at_index(), but it will not
12139  * emit signals or change state on @child.
12140  *
12141  * Since: 1.10
12142  */
12143 void
12144 clutter_actor_set_child_at_index (ClutterActor *self,
12145                                   ClutterActor *child,
12146                                   gint          index_)
12147 {
12148   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12149   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12150   g_return_if_fail (child->priv->parent == self);
12151   g_return_if_fail (index_ <= self->priv->n_children);
12152
12153   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12154       CLUTTER_ACTOR_IN_DESTRUCTION (child))
12155     return;
12156
12157   g_object_ref (child);
12158   clutter_actor_remove_child_internal (self, child, 0);
12159   clutter_actor_add_child_internal (self, child,
12160                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12161                                     insert_child_at_index,
12162                                     GINT_TO_POINTER (index_));
12163
12164   clutter_actor_queue_relayout (self);
12165 }
12166
12167 /**
12168  * clutter_actor_raise:
12169  * @self: A #ClutterActor
12170  * @below: (allow-none): A #ClutterActor to raise above.
12171  *
12172  * Puts @self above @below.
12173  *
12174  * Both actors must have the same parent, and the parent must implement
12175  * the #ClutterContainer interface
12176  *
12177  * This function calls clutter_container_raise_child() internally.
12178  *
12179  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12180  */
12181 void
12182 clutter_actor_raise (ClutterActor *self,
12183                      ClutterActor *below)
12184 {
12185   ClutterActor *parent;
12186
12187   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12188
12189   parent = clutter_actor_get_parent (self);
12190   if (parent == NULL)
12191     {
12192       g_warning ("%s: Actor '%s' is not inside a container",
12193                  G_STRFUNC,
12194                  _clutter_actor_get_debug_name (self));
12195       return;
12196     }
12197
12198   if (below != NULL)
12199     {
12200       if (parent != clutter_actor_get_parent (below))
12201         {
12202           g_warning ("%s Actor '%s' is not in the same container as "
12203                      "actor '%s'",
12204                      G_STRFUNC,
12205                      _clutter_actor_get_debug_name (self),
12206                      _clutter_actor_get_debug_name (below));
12207           return;
12208         }
12209     }
12210
12211   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12212 }
12213
12214 /**
12215  * clutter_actor_lower:
12216  * @self: A #ClutterActor
12217  * @above: (allow-none): A #ClutterActor to lower below
12218  *
12219  * Puts @self below @above.
12220  *
12221  * Both actors must have the same parent, and the parent must implement
12222  * the #ClutterContainer interface.
12223  *
12224  * This function calls clutter_container_lower_child() internally.
12225  *
12226  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12227  */
12228 void
12229 clutter_actor_lower (ClutterActor *self,
12230                      ClutterActor *above)
12231 {
12232   ClutterActor *parent;
12233
12234   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12235
12236   parent = clutter_actor_get_parent (self);
12237   if (parent == NULL)
12238     {
12239       g_warning ("%s: Actor of type %s is not inside a container",
12240                  G_STRFUNC,
12241                  _clutter_actor_get_debug_name (self));
12242       return;
12243     }
12244
12245   if (above)
12246     {
12247       if (parent != clutter_actor_get_parent (above))
12248         {
12249           g_warning ("%s: Actor '%s' is not in the same container as "
12250                      "actor '%s'",
12251                      G_STRFUNC,
12252                      _clutter_actor_get_debug_name (self),
12253                      _clutter_actor_get_debug_name (above));
12254           return;
12255         }
12256     }
12257
12258   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12259 }
12260
12261 /**
12262  * clutter_actor_raise_top:
12263  * @self: A #ClutterActor
12264  *
12265  * Raises @self to the top.
12266  *
12267  * This function calls clutter_actor_raise() internally.
12268  *
12269  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12270  *   a %NULL sibling, instead.
12271  */
12272 void
12273 clutter_actor_raise_top (ClutterActor *self)
12274 {
12275   clutter_actor_raise (self, NULL);
12276 }
12277
12278 /**
12279  * clutter_actor_lower_bottom:
12280  * @self: A #ClutterActor
12281  *
12282  * Lowers @self to the bottom.
12283  *
12284  * This function calls clutter_actor_lower() internally.
12285  *
12286  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12287  *   a %NULL sibling, instead.
12288  */
12289 void
12290 clutter_actor_lower_bottom (ClutterActor *self)
12291 {
12292   clutter_actor_lower (self, NULL);
12293 }
12294
12295 /*
12296  * Event handling
12297  */
12298
12299 /**
12300  * clutter_actor_event:
12301  * @actor: a #ClutterActor
12302  * @event: a #ClutterEvent
12303  * @capture: TRUE if event in in capture phase, FALSE otherwise.
12304  *
12305  * This function is used to emit an event on the main stage.
12306  * You should rarely need to use this function, except for
12307  * synthetising events.
12308  *
12309  * Return value: the return value from the signal emission: %TRUE
12310  *   if the actor handled the event, or %FALSE if the event was
12311  *   not handled
12312  *
12313  * Since: 0.6
12314  */
12315 gboolean
12316 clutter_actor_event (ClutterActor *actor,
12317                      ClutterEvent *event,
12318                      gboolean      capture)
12319 {
12320   gboolean retval = FALSE;
12321   gint signal_num = -1;
12322
12323   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12324   g_return_val_if_fail (event != NULL, FALSE);
12325
12326   g_object_ref (actor);
12327
12328   if (capture)
12329     {
12330       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12331                      event,
12332                      &retval);
12333       goto out;
12334     }
12335
12336   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12337
12338   if (!retval)
12339     {
12340       switch (event->type)
12341         {
12342         case CLUTTER_NOTHING:
12343           break;
12344         case CLUTTER_BUTTON_PRESS:
12345           signal_num = BUTTON_PRESS_EVENT;
12346           break;
12347         case CLUTTER_BUTTON_RELEASE:
12348           signal_num = BUTTON_RELEASE_EVENT;
12349           break;
12350         case CLUTTER_SCROLL:
12351           signal_num = SCROLL_EVENT;
12352           break;
12353         case CLUTTER_KEY_PRESS:
12354           signal_num = KEY_PRESS_EVENT;
12355           break;
12356         case CLUTTER_KEY_RELEASE:
12357           signal_num = KEY_RELEASE_EVENT;
12358           break;
12359         case CLUTTER_MOTION:
12360           signal_num = MOTION_EVENT;
12361           break;
12362         case CLUTTER_ENTER:
12363           signal_num = ENTER_EVENT;
12364           break;
12365         case CLUTTER_LEAVE:
12366           signal_num = LEAVE_EVENT;
12367           break;
12368         case CLUTTER_DELETE:
12369         case CLUTTER_DESTROY_NOTIFY:
12370         case CLUTTER_CLIENT_MESSAGE:
12371         default:
12372           signal_num = -1;
12373           break;
12374         }
12375
12376       if (signal_num != -1)
12377         g_signal_emit (actor, actor_signals[signal_num], 0,
12378                        event, &retval);
12379     }
12380
12381 out:
12382   g_object_unref (actor);
12383
12384   return retval;
12385 }
12386
12387 /**
12388  * clutter_actor_set_reactive:
12389  * @actor: a #ClutterActor
12390  * @reactive: whether the actor should be reactive to events
12391  *
12392  * Sets @actor as reactive. Reactive actors will receive events.
12393  *
12394  * Since: 0.6
12395  */
12396 void
12397 clutter_actor_set_reactive (ClutterActor *actor,
12398                             gboolean      reactive)
12399 {
12400   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12401
12402   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12403     return;
12404
12405   if (reactive)
12406     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12407   else
12408     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12409
12410   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12411 }
12412
12413 /**
12414  * clutter_actor_get_reactive:
12415  * @actor: a #ClutterActor
12416  *
12417  * Checks whether @actor is marked as reactive.
12418  *
12419  * Return value: %TRUE if the actor is reactive
12420  *
12421  * Since: 0.6
12422  */
12423 gboolean
12424 clutter_actor_get_reactive (ClutterActor *actor)
12425 {
12426   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12427
12428   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12429 }
12430
12431 /**
12432  * clutter_actor_get_anchor_point:
12433  * @self: a #ClutterActor
12434  * @anchor_x: (out): return location for the X coordinate of the anchor point
12435  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12436  *
12437  * Gets the current anchor point of the @actor in pixels.
12438  *
12439  * Since: 0.6
12440  */
12441 void
12442 clutter_actor_get_anchor_point (ClutterActor *self,
12443                                 gfloat       *anchor_x,
12444                                 gfloat       *anchor_y)
12445 {
12446   const ClutterTransformInfo *info;
12447
12448   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12449
12450   info = _clutter_actor_get_transform_info_or_defaults (self);
12451   clutter_anchor_coord_get_units (self, &info->anchor,
12452                                   anchor_x,
12453                                   anchor_y,
12454                                   NULL);
12455 }
12456
12457 /**
12458  * clutter_actor_set_anchor_point:
12459  * @self: a #ClutterActor
12460  * @anchor_x: X coordinate of the anchor point
12461  * @anchor_y: Y coordinate of the anchor point
12462  *
12463  * Sets an anchor point for @self. The anchor point is a point in the
12464  * coordinate space of an actor to which the actor position within its
12465  * parent is relative; the default is (0, 0), i.e. the top-left corner
12466  * of the actor.
12467  *
12468  * Since: 0.6
12469  */
12470 void
12471 clutter_actor_set_anchor_point (ClutterActor *self,
12472                                 gfloat        anchor_x,
12473                                 gfloat        anchor_y)
12474 {
12475   ClutterTransformInfo *info;
12476   ClutterActorPrivate *priv;
12477   gboolean changed = FALSE;
12478   gfloat old_anchor_x, old_anchor_y;
12479   GObject *obj;
12480
12481   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12482
12483   obj = G_OBJECT (self);
12484   priv = self->priv;
12485   info = _clutter_actor_get_transform_info (self);
12486
12487   g_object_freeze_notify (obj);
12488
12489   clutter_anchor_coord_get_units (self, &info->anchor,
12490                                   &old_anchor_x,
12491                                   &old_anchor_y,
12492                                   NULL);
12493
12494   if (info->anchor.is_fractional)
12495     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12496
12497   if (old_anchor_x != anchor_x)
12498     {
12499       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12500       changed = TRUE;
12501     }
12502
12503   if (old_anchor_y != anchor_y)
12504     {
12505       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12506       changed = TRUE;
12507     }
12508
12509   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12510
12511   if (changed)
12512     {
12513       priv->transform_valid = FALSE;
12514       clutter_actor_queue_redraw (self);
12515     }
12516
12517   g_object_thaw_notify (obj);
12518 }
12519
12520 /**
12521  * clutter_actor_get_anchor_point_gravity:
12522  * @self: a #ClutterActor
12523  *
12524  * Retrieves the anchor position expressed as a #ClutterGravity. If
12525  * the anchor point was specified using pixels or units this will
12526  * return %CLUTTER_GRAVITY_NONE.
12527  *
12528  * Return value: the #ClutterGravity used by the anchor point
12529  *
12530  * Since: 1.0
12531  */
12532 ClutterGravity
12533 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12534 {
12535   const ClutterTransformInfo *info;
12536
12537   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12538
12539   info = _clutter_actor_get_transform_info_or_defaults (self);
12540
12541   return clutter_anchor_coord_get_gravity (&info->anchor);
12542 }
12543
12544 /**
12545  * clutter_actor_move_anchor_point:
12546  * @self: a #ClutterActor
12547  * @anchor_x: X coordinate of the anchor point
12548  * @anchor_y: Y coordinate of the anchor point
12549  *
12550  * Sets an anchor point for the actor, and adjusts the actor postion so that
12551  * the relative position of the actor toward its parent remains the same.
12552  *
12553  * Since: 0.6
12554  */
12555 void
12556 clutter_actor_move_anchor_point (ClutterActor *self,
12557                                  gfloat        anchor_x,
12558                                  gfloat        anchor_y)
12559 {
12560   gfloat old_anchor_x, old_anchor_y;
12561   const ClutterTransformInfo *info;
12562
12563   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12564
12565   info = _clutter_actor_get_transform_info (self);
12566   clutter_anchor_coord_get_units (self, &info->anchor,
12567                                   &old_anchor_x,
12568                                   &old_anchor_y,
12569                                   NULL);
12570
12571   g_object_freeze_notify (G_OBJECT (self));
12572
12573   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12574
12575   if (self->priv->position_set)
12576     clutter_actor_move_by (self,
12577                            anchor_x - old_anchor_x,
12578                            anchor_y - old_anchor_y);
12579
12580   g_object_thaw_notify (G_OBJECT (self));
12581 }
12582
12583 /**
12584  * clutter_actor_move_anchor_point_from_gravity:
12585  * @self: a #ClutterActor
12586  * @gravity: #ClutterGravity.
12587  *
12588  * Sets an anchor point on the actor based on the given gravity, adjusting the
12589  * actor postion so that its relative position within its parent remains
12590  * unchanged.
12591  *
12592  * Since version 1.0 the anchor point will be stored as a gravity so
12593  * that if the actor changes size then the anchor point will move. For
12594  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12595  * and later double the size of the actor, the anchor point will move
12596  * to the bottom right.
12597  *
12598  * Since: 0.6
12599  */
12600 void
12601 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12602                                               ClutterGravity  gravity)
12603 {
12604   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12605   const ClutterTransformInfo *info;
12606   ClutterActorPrivate *priv;
12607
12608   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12609
12610   priv = self->priv;
12611   info = _clutter_actor_get_transform_info (self);
12612
12613   g_object_freeze_notify (G_OBJECT (self));
12614
12615   clutter_anchor_coord_get_units (self, &info->anchor,
12616                                   &old_anchor_x,
12617                                   &old_anchor_y,
12618                                   NULL);
12619   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12620   clutter_anchor_coord_get_units (self, &info->anchor,
12621                                   &new_anchor_x,
12622                                   &new_anchor_y,
12623                                   NULL);
12624
12625   if (priv->position_set)
12626     clutter_actor_move_by (self,
12627                            new_anchor_x - old_anchor_x,
12628                            new_anchor_y - old_anchor_y);
12629
12630   g_object_thaw_notify (G_OBJECT (self));
12631 }
12632
12633 /**
12634  * clutter_actor_set_anchor_point_from_gravity:
12635  * @self: a #ClutterActor
12636  * @gravity: #ClutterGravity.
12637  *
12638  * Sets an anchor point on the actor, based on the given gravity (this is a
12639  * convenience function wrapping clutter_actor_set_anchor_point()).
12640  *
12641  * Since version 1.0 the anchor point will be stored as a gravity so
12642  * that if the actor changes size then the anchor point will move. For
12643  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12644  * and later double the size of the actor, the anchor point will move
12645  * to the bottom right.
12646  *
12647  * Since: 0.6
12648  */
12649 void
12650 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12651                                              ClutterGravity  gravity)
12652 {
12653   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12654
12655   if (gravity == CLUTTER_GRAVITY_NONE)
12656     clutter_actor_set_anchor_point (self, 0, 0);
12657   else
12658     {
12659       GObject *obj = G_OBJECT (self);
12660       ClutterTransformInfo *info;
12661
12662       g_object_freeze_notify (obj);
12663
12664       info = _clutter_actor_get_transform_info (self);
12665       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12666
12667       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12668       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12669       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12670
12671       self->priv->transform_valid = FALSE;
12672
12673       clutter_actor_queue_redraw (self);
12674
12675       g_object_thaw_notify (obj);
12676     }
12677 }
12678
12679 static void
12680 clutter_actor_store_content_box (ClutterActor *self,
12681                                  const ClutterActorBox *box)
12682 {
12683   if (box != NULL)
12684     {
12685       self->priv->content_box = *box;
12686       self->priv->content_box_valid = TRUE;
12687     }
12688   else
12689     self->priv->content_box_valid = FALSE;
12690
12691   clutter_actor_queue_redraw (self);
12692
12693   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12694 }
12695
12696 static void
12697 clutter_container_iface_init (ClutterContainerIface *iface)
12698 {
12699   /* we don't override anything, as ClutterContainer already has a default
12700    * implementation that we can use, and which calls into our own API.
12701    */
12702 }
12703
12704 typedef enum
12705 {
12706   PARSE_X,
12707   PARSE_Y,
12708   PARSE_WIDTH,
12709   PARSE_HEIGHT,
12710   PARSE_ANCHOR_X,
12711   PARSE_ANCHOR_Y
12712 } ParseDimension;
12713
12714 static gfloat
12715 parse_units (ClutterActor   *self,
12716              ParseDimension  dimension,
12717              JsonNode       *node)
12718 {
12719   GValue value = G_VALUE_INIT;
12720   gfloat retval = 0;
12721
12722   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12723     return 0;
12724
12725   json_node_get_value (node, &value);
12726
12727   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12728     {
12729       retval = (gfloat) g_value_get_int64 (&value);
12730     }
12731   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12732     {
12733       retval = g_value_get_double (&value);
12734     }
12735   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12736     {
12737       ClutterUnits units;
12738       gboolean res;
12739
12740       res = clutter_units_from_string (&units, g_value_get_string (&value));
12741       if (res)
12742         retval = clutter_units_to_pixels (&units);
12743       else
12744         {
12745           g_warning ("Invalid value '%s': integers, strings or floating point "
12746                      "values can be used for the x, y, width and height "
12747                      "properties. Valid modifiers for strings are 'px', 'mm', "
12748                      "'pt' and 'em'.",
12749                      g_value_get_string (&value));
12750           retval = 0;
12751         }
12752     }
12753   else
12754     {
12755       g_warning ("Invalid value of type '%s': integers, strings of floating "
12756                  "point values can be used for the x, y, width, height "
12757                  "anchor-x and anchor-y properties.",
12758                  g_type_name (G_VALUE_TYPE (&value)));
12759     }
12760
12761   g_value_unset (&value);
12762
12763   return retval;
12764 }
12765
12766 typedef struct {
12767   ClutterRotateAxis axis;
12768
12769   gdouble angle;
12770
12771   gfloat center_x;
12772   gfloat center_y;
12773   gfloat center_z;
12774 } RotationInfo;
12775
12776 static inline gboolean
12777 parse_rotation_array (ClutterActor *actor,
12778                       JsonArray    *array,
12779                       RotationInfo *info)
12780 {
12781   JsonNode *element;
12782
12783   if (json_array_get_length (array) != 2)
12784     return FALSE;
12785
12786   /* angle */
12787   element = json_array_get_element (array, 0);
12788   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12789     info->angle = json_node_get_double (element);
12790   else
12791     return FALSE;
12792
12793   /* center */
12794   element = json_array_get_element (array, 1);
12795   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12796     {
12797       JsonArray *center = json_node_get_array (element);
12798
12799       if (json_array_get_length (center) != 2)
12800         return FALSE;
12801
12802       switch (info->axis)
12803         {
12804         case CLUTTER_X_AXIS:
12805           info->center_y = parse_units (actor, PARSE_Y,
12806                                         json_array_get_element (center, 0));
12807           info->center_z = parse_units (actor, PARSE_Y,
12808                                         json_array_get_element (center, 1));
12809           return TRUE;
12810
12811         case CLUTTER_Y_AXIS:
12812           info->center_x = parse_units (actor, PARSE_X,
12813                                         json_array_get_element (center, 0));
12814           info->center_z = parse_units (actor, PARSE_X,
12815                                         json_array_get_element (center, 1));
12816           return TRUE;
12817
12818         case CLUTTER_Z_AXIS:
12819           info->center_x = parse_units (actor, PARSE_X,
12820                                         json_array_get_element (center, 0));
12821           info->center_y = parse_units (actor, PARSE_Y,
12822                                         json_array_get_element (center, 1));
12823           return TRUE;
12824         }
12825     }
12826
12827   return FALSE;
12828 }
12829
12830 static gboolean
12831 parse_rotation (ClutterActor *actor,
12832                 JsonNode     *node,
12833                 RotationInfo *info)
12834 {
12835   JsonArray *array;
12836   guint len, i;
12837   gboolean retval = FALSE;
12838
12839   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12840     {
12841       g_warning ("Invalid node of type '%s' found, expecting an array",
12842                  json_node_type_name (node));
12843       return FALSE;
12844     }
12845
12846   array = json_node_get_array (node);
12847   len = json_array_get_length (array);
12848
12849   for (i = 0; i < len; i++)
12850     {
12851       JsonNode *element = json_array_get_element (array, i);
12852       JsonObject *object;
12853       JsonNode *member;
12854
12855       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12856         {
12857           g_warning ("Invalid node of type '%s' found, expecting an object",
12858                      json_node_type_name (element));
12859           return FALSE;
12860         }
12861
12862       object = json_node_get_object (element);
12863
12864       if (json_object_has_member (object, "x-axis"))
12865         {
12866           member = json_object_get_member (object, "x-axis");
12867
12868           info->axis = CLUTTER_X_AXIS;
12869
12870           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12871             {
12872               info->angle = json_node_get_double (member);
12873               retval = TRUE;
12874             }
12875           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12876             retval = parse_rotation_array (actor,
12877                                            json_node_get_array (member),
12878                                            info);
12879           else
12880             retval = FALSE;
12881         }
12882       else if (json_object_has_member (object, "y-axis"))
12883         {
12884           member = json_object_get_member (object, "y-axis");
12885
12886           info->axis = CLUTTER_Y_AXIS;
12887
12888           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12889             {
12890               info->angle = json_node_get_double (member);
12891               retval = TRUE;
12892             }
12893           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12894             retval = parse_rotation_array (actor,
12895                                            json_node_get_array (member),
12896                                            info);
12897           else
12898             retval = FALSE;
12899         }
12900       else if (json_object_has_member (object, "z-axis"))
12901         {
12902           member = json_object_get_member (object, "z-axis");
12903
12904           info->axis = CLUTTER_Z_AXIS;
12905
12906           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12907             {
12908               info->angle = json_node_get_double (member);
12909               retval = TRUE;
12910             }
12911           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12912             retval = parse_rotation_array (actor,
12913                                            json_node_get_array (member),
12914                                            info);
12915           else
12916             retval = FALSE;
12917         }
12918     }
12919
12920   return retval;
12921 }
12922
12923 static GSList *
12924 parse_actor_metas (ClutterScript *script,
12925                    ClutterActor  *actor,
12926                    JsonNode      *node)
12927 {
12928   GList *elements, *l;
12929   GSList *retval = NULL;
12930
12931   if (!JSON_NODE_HOLDS_ARRAY (node))
12932     return NULL;
12933
12934   elements = json_array_get_elements (json_node_get_array (node));
12935
12936   for (l = elements; l != NULL; l = l->next)
12937     {
12938       JsonNode *element = l->data;
12939       const gchar *id_ = _clutter_script_get_id_from_node (element);
12940       GObject *meta;
12941
12942       if (id_ == NULL || *id_ == '\0')
12943         continue;
12944
12945       meta = clutter_script_get_object (script, id_);
12946       if (meta == NULL)
12947         continue;
12948
12949       retval = g_slist_prepend (retval, meta);
12950     }
12951
12952   g_list_free (elements);
12953
12954   return g_slist_reverse (retval);
12955 }
12956
12957 static GSList *
12958 parse_behaviours (ClutterScript *script,
12959                   ClutterActor  *actor,
12960                   JsonNode      *node)
12961 {
12962   GList *elements, *l;
12963   GSList *retval = NULL;
12964
12965   if (!JSON_NODE_HOLDS_ARRAY (node))
12966     return NULL;
12967
12968   elements = json_array_get_elements (json_node_get_array (node));
12969
12970   for (l = elements; l != NULL; l = l->next)
12971     {
12972       JsonNode *element = l->data;
12973       const gchar *id_ = _clutter_script_get_id_from_node (element);
12974       GObject *behaviour;
12975
12976       if (id_ == NULL || *id_ == '\0')
12977         continue;
12978
12979       behaviour = clutter_script_get_object (script, id_);
12980       if (behaviour == NULL)
12981         continue;
12982
12983       retval = g_slist_prepend (retval, behaviour);
12984     }
12985
12986   g_list_free (elements);
12987
12988   return g_slist_reverse (retval);
12989 }
12990
12991 static gboolean
12992 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12993                                  ClutterScript     *script,
12994                                  GValue            *value,
12995                                  const gchar       *name,
12996                                  JsonNode          *node)
12997 {
12998   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12999   gboolean retval = FALSE;
13000
13001   if ((name[0] == 'x' && name[1] == '\0') ||
13002       (name[0] == 'y' && name[1] == '\0') ||
13003       (strcmp (name, "width") == 0) ||
13004       (strcmp (name, "height") == 0) ||
13005       (strcmp (name, "anchor_x") == 0) ||
13006       (strcmp (name, "anchor_y") == 0))
13007     {
13008       ParseDimension dimension;
13009       gfloat units;
13010
13011       if (name[0] == 'x')
13012         dimension = PARSE_X;
13013       else if (name[0] == 'y')
13014         dimension = PARSE_Y;
13015       else if (name[0] == 'w')
13016         dimension = PARSE_WIDTH;
13017       else if (name[0] == 'h')
13018         dimension = PARSE_HEIGHT;
13019       else if (name[0] == 'a' && name[7] == 'x')
13020         dimension = PARSE_ANCHOR_X;
13021       else if (name[0] == 'a' && name[7] == 'y')
13022         dimension = PARSE_ANCHOR_Y;
13023       else
13024         return FALSE;
13025
13026       units = parse_units (actor, dimension, node);
13027
13028       /* convert back to pixels: all properties are pixel-based */
13029       g_value_init (value, G_TYPE_FLOAT);
13030       g_value_set_float (value, units);
13031
13032       retval = TRUE;
13033     }
13034   else if (strcmp (name, "rotation") == 0)
13035     {
13036       RotationInfo *info;
13037
13038       info = g_slice_new0 (RotationInfo);
13039       retval = parse_rotation (actor, node, info);
13040
13041       if (retval)
13042         {
13043           g_value_init (value, G_TYPE_POINTER);
13044           g_value_set_pointer (value, info);
13045         }
13046       else
13047         g_slice_free (RotationInfo, info);
13048     }
13049   else if (strcmp (name, "behaviours") == 0)
13050     {
13051       GSList *l;
13052
13053 #ifdef CLUTTER_ENABLE_DEBUG
13054       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
13055         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
13056                                      "and it should not be used in newly "
13057                                      "written ClutterScript definitions.");
13058 #endif
13059
13060       l = parse_behaviours (script, actor, node);
13061
13062       g_value_init (value, G_TYPE_POINTER);
13063       g_value_set_pointer (value, l);
13064
13065       retval = TRUE;
13066     }
13067   else if (strcmp (name, "actions") == 0 ||
13068            strcmp (name, "constraints") == 0 ||
13069            strcmp (name, "effects") == 0)
13070     {
13071       GSList *l;
13072
13073       l = parse_actor_metas (script, actor, node);
13074
13075       g_value_init (value, G_TYPE_POINTER);
13076       g_value_set_pointer (value, l);
13077
13078       retval = TRUE;
13079     }
13080
13081   return retval;
13082 }
13083
13084 static void
13085 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
13086                                    ClutterScript     *script,
13087                                    const gchar       *name,
13088                                    const GValue      *value)
13089 {
13090   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13091
13092 #ifdef CLUTTER_ENABLE_DEBUG
13093   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
13094     {
13095       gchar *tmp = g_strdup_value_contents (value);
13096
13097       CLUTTER_NOTE (SCRIPT,
13098                     "in ClutterActor::set_custom_property('%s') = %s",
13099                     name,
13100                     tmp);
13101
13102       g_free (tmp);
13103     }
13104 #endif /* CLUTTER_ENABLE_DEBUG */
13105
13106   if (strcmp (name, "rotation") == 0)
13107     {
13108       RotationInfo *info;
13109
13110       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13111         return;
13112
13113       info = g_value_get_pointer (value);
13114
13115       clutter_actor_set_rotation (actor,
13116                                   info->axis, info->angle,
13117                                   info->center_x,
13118                                   info->center_y,
13119                                   info->center_z);
13120
13121       g_slice_free (RotationInfo, info);
13122
13123       return;
13124     }
13125
13126   if (strcmp (name, "behaviours") == 0)
13127     {
13128       GSList *behaviours, *l;
13129
13130       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13131         return;
13132
13133       behaviours = g_value_get_pointer (value);
13134       for (l = behaviours; l != NULL; l = l->next)
13135         {
13136           ClutterBehaviour *behaviour = l->data;
13137
13138           clutter_behaviour_apply (behaviour, actor);
13139         }
13140
13141       g_slist_free (behaviours);
13142
13143       return;
13144     }
13145
13146   if (strcmp (name, "actions") == 0 ||
13147       strcmp (name, "constraints") == 0 ||
13148       strcmp (name, "effects") == 0)
13149     {
13150       GSList *metas, *l;
13151
13152       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13153         return;
13154
13155       metas = g_value_get_pointer (value);
13156       for (l = metas; l != NULL; l = l->next)
13157         {
13158           if (name[0] == 'a')
13159             clutter_actor_add_action (actor, l->data);
13160
13161           if (name[0] == 'c')
13162             clutter_actor_add_constraint (actor, l->data);
13163
13164           if (name[0] == 'e')
13165             clutter_actor_add_effect (actor, l->data);
13166         }
13167
13168       g_slist_free (metas);
13169
13170       return;
13171     }
13172
13173   g_object_set_property (G_OBJECT (scriptable), name, value);
13174 }
13175
13176 static void
13177 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13178 {
13179   iface->parse_custom_node = clutter_actor_parse_custom_node;
13180   iface->set_custom_property = clutter_actor_set_custom_property;
13181 }
13182
13183 static ClutterActorMeta *
13184 get_meta_from_animation_property (ClutterActor  *actor,
13185                                   const gchar   *name,
13186                                   gchar        **name_p)
13187 {
13188   ClutterActorPrivate *priv = actor->priv;
13189   ClutterActorMeta *meta = NULL;
13190   gchar **tokens;
13191
13192   /* if this is not a special property, fall through */
13193   if (name[0] != '@')
13194     return NULL;
13195
13196   /* detect the properties named using the following spec:
13197    *
13198    *   @<section>.<meta-name>.<property-name>
13199    *
13200    * where <section> can be one of the following:
13201    *
13202    *   - actions
13203    *   - constraints
13204    *   - effects
13205    *
13206    * and <meta-name> is the name set on a specific ActorMeta
13207    */
13208
13209   tokens = g_strsplit (name + 1, ".", -1);
13210   if (tokens == NULL || g_strv_length (tokens) != 3)
13211     {
13212       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13213                     name + 1);
13214       g_strfreev (tokens);
13215       return NULL;
13216     }
13217
13218   if (strcmp (tokens[0], "actions") == 0)
13219     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13220
13221   if (strcmp (tokens[0], "constraints") == 0)
13222     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13223
13224   if (strcmp (tokens[0], "effects") == 0)
13225     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13226
13227   if (name_p != NULL)
13228     *name_p = g_strdup (tokens[2]);
13229
13230   CLUTTER_NOTE (ANIMATION,
13231                 "Looking for property '%s' of object '%s' in section '%s'",
13232                 tokens[2],
13233                 tokens[1],
13234                 tokens[0]);
13235
13236   g_strfreev (tokens);
13237
13238   return meta;
13239 }
13240
13241 static GParamSpec *
13242 clutter_actor_find_property (ClutterAnimatable *animatable,
13243                              const gchar       *property_name)
13244 {
13245   ClutterActorMeta *meta = NULL;
13246   GObjectClass *klass = NULL;
13247   GParamSpec *pspec = NULL;
13248   gchar *p_name = NULL;
13249
13250   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13251                                            property_name,
13252                                            &p_name);
13253
13254   if (meta != NULL)
13255     {
13256       klass = G_OBJECT_GET_CLASS (meta);
13257
13258       pspec = g_object_class_find_property (klass, p_name);
13259     }
13260   else
13261     {
13262       klass = G_OBJECT_GET_CLASS (animatable);
13263
13264       pspec = g_object_class_find_property (klass, property_name);
13265     }
13266
13267   g_free (p_name);
13268
13269   return pspec;
13270 }
13271
13272 static void
13273 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13274                                  const gchar       *property_name,
13275                                  GValue            *initial)
13276 {
13277   ClutterActorMeta *meta = NULL;
13278   gchar *p_name = NULL;
13279
13280   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13281                                            property_name,
13282                                            &p_name);
13283
13284   if (meta != NULL)
13285     g_object_get_property (G_OBJECT (meta), p_name, initial);
13286   else
13287     g_object_get_property (G_OBJECT (animatable), property_name, initial);
13288
13289   g_free (p_name);
13290 }
13291
13292 /*
13293  * clutter_actor_set_animatable_property:
13294  * @actor: a #ClutterActor
13295  * @prop_id: the paramspec id
13296  * @value: the value to set
13297  * @pspec: the paramspec
13298  *
13299  * Sets values of animatable properties.
13300  *
13301  * This is a variant of clutter_actor_set_property() that gets called
13302  * by the #ClutterAnimatable implementation of #ClutterActor for the
13303  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13304  * #GParamSpec.
13305  *
13306  * Unlike the implementation of #GObjectClass.set_property(), this
13307  * function will not update the interval if a transition involving an
13308  * animatable property is in progress - this avoids cycles with the
13309  * transition API calling the public API.
13310  */
13311 static void
13312 clutter_actor_set_animatable_property (ClutterActor *actor,
13313                                        guint         prop_id,
13314                                        const GValue *value,
13315                                        GParamSpec   *pspec)
13316 {
13317   GObject *obj = G_OBJECT (actor);
13318
13319   g_object_freeze_notify (obj);
13320
13321   switch (prop_id)
13322     {
13323     case PROP_X:
13324       clutter_actor_set_x_internal (actor, g_value_get_float (value));
13325       break;
13326
13327     case PROP_Y:
13328       clutter_actor_set_y_internal (actor, g_value_get_float (value));
13329       break;
13330
13331     case PROP_POSITION:
13332       clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13333       break;
13334
13335     case PROP_WIDTH:
13336       clutter_actor_set_width_internal (actor, g_value_get_float (value));
13337       break;
13338
13339     case PROP_HEIGHT:
13340       clutter_actor_set_height_internal (actor, g_value_get_float (value));
13341       break;
13342
13343     case PROP_SIZE:
13344       clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13345       break;
13346
13347     case PROP_DEPTH:
13348       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13349       break;
13350
13351     case PROP_OPACITY:
13352       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13353       break;
13354
13355     case PROP_BACKGROUND_COLOR:
13356       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13357       break;
13358
13359     case PROP_SCALE_X:
13360       clutter_actor_set_scale_factor_internal (actor,
13361                                                g_value_get_double (value),
13362                                                pspec);
13363       break;
13364
13365     case PROP_SCALE_Y:
13366       clutter_actor_set_scale_factor_internal (actor,
13367                                                g_value_get_double (value),
13368                                                pspec);
13369       break;
13370
13371     case PROP_ROTATION_ANGLE_X:
13372       clutter_actor_set_rotation_angle_internal (actor,
13373                                                  CLUTTER_X_AXIS,
13374                                                  g_value_get_double (value));
13375       break;
13376
13377     case PROP_ROTATION_ANGLE_Y:
13378       clutter_actor_set_rotation_angle_internal (actor,
13379                                                  CLUTTER_Y_AXIS,
13380                                                  g_value_get_double (value));
13381       break;
13382
13383     case PROP_ROTATION_ANGLE_Z:
13384       clutter_actor_set_rotation_angle_internal (actor,
13385                                                  CLUTTER_Z_AXIS,
13386                                                  g_value_get_double (value));
13387       break;
13388
13389     case PROP_CONTENT_BOX:
13390       clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13391       break;
13392
13393     default:
13394       g_object_set_property (obj, pspec->name, value);
13395       break;
13396     }
13397
13398   g_object_thaw_notify (obj);
13399 }
13400
13401 static void
13402 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13403                                const gchar       *property_name,
13404                                const GValue      *final)
13405 {
13406   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13407   ClutterActorMeta *meta = NULL;
13408   gchar *p_name = NULL;
13409
13410   meta = get_meta_from_animation_property (actor,
13411                                            property_name,
13412                                            &p_name);
13413   if (meta != NULL)
13414     g_object_set_property (G_OBJECT (meta), p_name, final);
13415   else
13416     {
13417       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13418       GParamSpec *pspec;
13419
13420       pspec = g_object_class_find_property (obj_class, property_name);
13421
13422       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13423         {
13424           /* XXX - I'm going to the special hell for this */
13425           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13426         }
13427       else
13428         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13429     }
13430
13431   g_free (p_name);
13432 }
13433
13434 static void
13435 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13436 {
13437   iface->find_property = clutter_actor_find_property;
13438   iface->get_initial_state = clutter_actor_get_initial_state;
13439   iface->set_final_state = clutter_actor_set_final_state;
13440 }
13441
13442 /**
13443  * clutter_actor_transform_stage_point:
13444  * @self: A #ClutterActor
13445  * @x: (in): x screen coordinate of the point to unproject
13446  * @y: (in): y screen coordinate of the point to unproject
13447  * @x_out: (out): return location for the unprojected x coordinance
13448  * @y_out: (out): return location for the unprojected y coordinance
13449  *
13450  * This function translates screen coordinates (@x, @y) to
13451  * coordinates relative to the actor. For example, it can be used to translate
13452  * screen events from global screen coordinates into actor-local coordinates.
13453  *
13454  * The conversion can fail, notably if the transform stack results in the
13455  * actor being projected on the screen as a mere line.
13456  *
13457  * The conversion should not be expected to be pixel-perfect due to the
13458  * nature of the operation. In general the error grows when the skewing
13459  * of the actor rectangle on screen increases.
13460  *
13461  * <note><para>This function can be computationally intensive.</para></note>
13462  *
13463  * <note><para>This function only works when the allocation is up-to-date,
13464  * i.e. inside of paint().</para></note>
13465  *
13466  * Return value: %TRUE if conversion was successful.
13467  *
13468  * Since: 0.6
13469  */
13470 gboolean
13471 clutter_actor_transform_stage_point (ClutterActor *self,
13472                                      gfloat        x,
13473                                      gfloat        y,
13474                                      gfloat       *x_out,
13475                                      gfloat       *y_out)
13476 {
13477   ClutterVertex v[4];
13478   float ST[3][3];
13479   float RQ[3][3];
13480   int du, dv, xi, yi;
13481   float px, py;
13482   float xf, yf, wf, det;
13483   ClutterActorPrivate *priv;
13484
13485   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13486
13487   priv = self->priv;
13488
13489   /* This implementation is based on the quad -> quad projection algorithm
13490    * described by Paul Heckbert in:
13491    *
13492    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13493    *
13494    * and the sample implementation at:
13495    *
13496    *   http://www.cs.cmu.edu/~ph/src/texfund/
13497    *
13498    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13499    * quad to rectangle only, which significantly simplifies things; the
13500    * function calls have been unrolled, and most of the math is done in fixed
13501    * point.
13502    */
13503
13504   clutter_actor_get_abs_allocation_vertices (self, v);
13505
13506   /* Keeping these as ints simplifies the multiplication (no significant
13507    * loss of precision here).
13508    */
13509   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13510   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13511
13512   if (!du || !dv)
13513     return FALSE;
13514
13515 #define UX2FP(x)        (x)
13516 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13517
13518   /* First, find mapping from unit uv square to xy quadrilateral; this
13519    * equivalent to the pmap_square_quad() functions in the sample
13520    * implementation, which we can simplify, since our target is always
13521    * a rectangle.
13522    */
13523   px = v[0].x - v[1].x + v[3].x - v[2].x;
13524   py = v[0].y - v[1].y + v[3].y - v[2].y;
13525
13526   if (!px && !py)
13527     {
13528       /* affine transform */
13529       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13530       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13531       RQ[2][0] = UX2FP (v[0].x);
13532       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13533       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13534       RQ[2][1] = UX2FP (v[0].y);
13535       RQ[0][2] = 0;
13536       RQ[1][2] = 0;
13537       RQ[2][2] = 1.0;
13538     }
13539   else
13540     {
13541       /* projective transform */
13542       double dx1, dx2, dy1, dy2, del;
13543
13544       dx1 = UX2FP (v[1].x - v[3].x);
13545       dx2 = UX2FP (v[2].x - v[3].x);
13546       dy1 = UX2FP (v[1].y - v[3].y);
13547       dy2 = UX2FP (v[2].y - v[3].y);
13548
13549       del = DET2FP (dx1, dx2, dy1, dy2);
13550       if (!del)
13551         return FALSE;
13552
13553       /*
13554        * The division here needs to be done in floating point for
13555        * precisions reasons.
13556        */
13557       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13558       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13559       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13560       RQ[2][2] = 1.0;
13561       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13562       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13563       RQ[2][0] = UX2FP (v[0].x);
13564       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13565       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13566       RQ[2][1] = UX2FP (v[0].y);
13567     }
13568
13569   /*
13570    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13571    * square. Since our rectangle is based at 0,0 we only need to scale.
13572    */
13573   RQ[0][0] /= du;
13574   RQ[1][0] /= dv;
13575   RQ[0][1] /= du;
13576   RQ[1][1] /= dv;
13577   RQ[0][2] /= du;
13578   RQ[1][2] /= dv;
13579
13580   /*
13581    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13582    * inverse of that.
13583    */
13584   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13585   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13586   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13587   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13588   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13589   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13590   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13591   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13592   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13593
13594   /*
13595    * Check the resulting matrix is OK.
13596    */
13597   det = (RQ[0][0] * ST[0][0])
13598       + (RQ[0][1] * ST[0][1])
13599       + (RQ[0][2] * ST[0][2]);
13600   if (!det)
13601     return FALSE;
13602
13603   /*
13604    * Now transform our point with the ST matrix; the notional w
13605    * coordinate is 1, hence the last part is simply added.
13606    */
13607   xi = (int) x;
13608   yi = (int) y;
13609
13610   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13611   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13612   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13613
13614   if (x_out)
13615     *x_out = xf / wf;
13616
13617   if (y_out)
13618     *y_out = yf / wf;
13619
13620 #undef UX2FP
13621 #undef DET2FP
13622
13623   return TRUE;
13624 }
13625
13626 /**
13627  * clutter_actor_is_rotated:
13628  * @self: a #ClutterActor
13629  *
13630  * Checks whether any rotation is applied to the actor.
13631  *
13632  * Return value: %TRUE if the actor is rotated.
13633  *
13634  * Since: 0.6
13635  */
13636 gboolean
13637 clutter_actor_is_rotated (ClutterActor *self)
13638 {
13639   const ClutterTransformInfo *info;
13640
13641   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13642
13643   info = _clutter_actor_get_transform_info_or_defaults (self);
13644
13645   if (info->rx_angle || info->ry_angle || info->rz_angle)
13646     return TRUE;
13647
13648   return FALSE;
13649 }
13650
13651 /**
13652  * clutter_actor_is_scaled:
13653  * @self: a #ClutterActor
13654  *
13655  * Checks whether the actor is scaled in either dimension.
13656  *
13657  * Return value: %TRUE if the actor is scaled.
13658  *
13659  * Since: 0.6
13660  */
13661 gboolean
13662 clutter_actor_is_scaled (ClutterActor *self)
13663 {
13664   const ClutterTransformInfo *info;
13665
13666   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13667
13668   info = _clutter_actor_get_transform_info_or_defaults (self);
13669
13670   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13671     return TRUE;
13672
13673   return FALSE;
13674 }
13675
13676 ClutterActor *
13677 _clutter_actor_get_stage_internal (ClutterActor *actor)
13678 {
13679   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13680     actor = actor->priv->parent;
13681
13682   return actor;
13683 }
13684
13685 /**
13686  * clutter_actor_get_stage:
13687  * @actor: a #ClutterActor
13688  *
13689  * Retrieves the #ClutterStage where @actor is contained.
13690  *
13691  * Return value: (transfer none) (type Clutter.Stage): the stage
13692  *   containing the actor, or %NULL
13693  *
13694  * Since: 0.8
13695  */
13696 ClutterActor *
13697 clutter_actor_get_stage (ClutterActor *actor)
13698 {
13699   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13700
13701   return _clutter_actor_get_stage_internal (actor);
13702 }
13703
13704 /**
13705  * clutter_actor_allocate_available_size:
13706  * @self: a #ClutterActor
13707  * @x: the actor's X coordinate
13708  * @y: the actor's Y coordinate
13709  * @available_width: the maximum available width, or -1 to use the
13710  *   actor's natural width
13711  * @available_height: the maximum available height, or -1 to use the
13712  *   actor's natural height
13713  * @flags: flags controlling the allocation
13714  *
13715  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13716  * preferred size, but limiting it to the maximum available width
13717  * and height provided.
13718  *
13719  * This function will do the right thing when dealing with the
13720  * actor's request mode.
13721  *
13722  * The implementation of this function is equivalent to:
13723  *
13724  * |[
13725  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13726  *     {
13727  *       clutter_actor_get_preferred_width (self, available_height,
13728  *                                          &amp;min_width,
13729  *                                          &amp;natural_width);
13730  *       width = CLAMP (natural_width, min_width, available_width);
13731  *
13732  *       clutter_actor_get_preferred_height (self, width,
13733  *                                           &amp;min_height,
13734  *                                           &amp;natural_height);
13735  *       height = CLAMP (natural_height, min_height, available_height);
13736  *     }
13737  *   else
13738  *     {
13739  *       clutter_actor_get_preferred_height (self, available_width,
13740  *                                           &amp;min_height,
13741  *                                           &amp;natural_height);
13742  *       height = CLAMP (natural_height, min_height, available_height);
13743  *
13744  *       clutter_actor_get_preferred_width (self, height,
13745  *                                          &amp;min_width,
13746  *                                          &amp;natural_width);
13747  *       width = CLAMP (natural_width, min_width, available_width);
13748  *     }
13749  *
13750  *   box.x1 = x; box.y1 = y;
13751  *   box.x2 = box.x1 + available_width;
13752  *   box.y2 = box.y1 + available_height;
13753  *   clutter_actor_allocate (self, &amp;box, flags);
13754  * ]|
13755  *
13756  * This function can be used by fluid layout managers to allocate
13757  * an actor's preferred size without making it bigger than the area
13758  * available for the container.
13759  *
13760  * Since: 1.0
13761  */
13762 void
13763 clutter_actor_allocate_available_size (ClutterActor           *self,
13764                                        gfloat                  x,
13765                                        gfloat                  y,
13766                                        gfloat                  available_width,
13767                                        gfloat                  available_height,
13768                                        ClutterAllocationFlags  flags)
13769 {
13770   ClutterActorPrivate *priv;
13771   gfloat width, height;
13772   gfloat min_width, min_height;
13773   gfloat natural_width, natural_height;
13774   ClutterActorBox box;
13775
13776   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13777
13778   priv = self->priv;
13779
13780   width = height = 0.0;
13781
13782   switch (priv->request_mode)
13783     {
13784     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13785       clutter_actor_get_preferred_width (self, available_height,
13786                                          &min_width,
13787                                          &natural_width);
13788       width  = CLAMP (natural_width, min_width, available_width);
13789
13790       clutter_actor_get_preferred_height (self, width,
13791                                           &min_height,
13792                                           &natural_height);
13793       height = CLAMP (natural_height, min_height, available_height);
13794       break;
13795
13796     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13797       clutter_actor_get_preferred_height (self, available_width,
13798                                           &min_height,
13799                                           &natural_height);
13800       height = CLAMP (natural_height, min_height, available_height);
13801
13802       clutter_actor_get_preferred_width (self, height,
13803                                          &min_width,
13804                                          &natural_width);
13805       width  = CLAMP (natural_width, min_width, available_width);
13806       break;
13807     }
13808
13809
13810   box.x1 = x;
13811   box.y1 = y;
13812   box.x2 = box.x1 + width;
13813   box.y2 = box.y1 + height;
13814   clutter_actor_allocate (self, &box, flags);
13815 }
13816
13817 /**
13818  * clutter_actor_allocate_preferred_size:
13819  * @self: a #ClutterActor
13820  * @flags: flags controlling the allocation
13821  *
13822  * Allocates the natural size of @self.
13823  *
13824  * This function is a utility call for #ClutterActor implementations
13825  * that allocates the actor's preferred natural size. It can be used
13826  * by fixed layout managers (like #ClutterGroup or so called
13827  * 'composite actors') inside the ClutterActor::allocate
13828  * implementation to give each child exactly how much space it
13829  * requires.
13830  *
13831  * This function is not meant to be used by applications. It is also
13832  * not meant to be used outside the implementation of the
13833  * ClutterActor::allocate virtual function.
13834  *
13835  * Since: 0.8
13836  */
13837 void
13838 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13839                                        ClutterAllocationFlags  flags)
13840 {
13841   gfloat actor_x, actor_y;
13842   gfloat natural_width, natural_height;
13843   ClutterActorBox actor_box;
13844
13845   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13846
13847   actor_x = clutter_actor_get_x (self);
13848   actor_y = clutter_actor_get_y (self);
13849
13850   clutter_actor_get_preferred_size (self,
13851                                     NULL, NULL,
13852                                     &natural_width,
13853                                     &natural_height);
13854
13855   actor_box.x1 = actor_x;
13856   actor_box.y1 = actor_y;
13857   actor_box.x2 = actor_box.x1 + natural_width;
13858   actor_box.y2 = actor_box.y1 + natural_height;
13859
13860   clutter_actor_allocate (self, &actor_box, flags);
13861 }
13862
13863 /**
13864  * clutter_actor_allocate_align_fill:
13865  * @self: a #ClutterActor
13866  * @box: a #ClutterActorBox, containing the available width and height
13867  * @x_align: the horizontal alignment, between 0 and 1
13868  * @y_align: the vertical alignment, between 0 and 1
13869  * @x_fill: whether the actor should fill horizontally
13870  * @y_fill: whether the actor should fill vertically
13871  * @flags: allocation flags to be passed to clutter_actor_allocate()
13872  *
13873  * Allocates @self by taking into consideration the available allocation
13874  * area; an alignment factor on either axis; and whether the actor should
13875  * fill the allocation on either axis.
13876  *
13877  * The @box should contain the available allocation width and height;
13878  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13879  * allocation will be offset by their value.
13880  *
13881  * This function takes into consideration the geometry request specified by
13882  * the #ClutterActor:request-mode property, and the text direction.
13883  *
13884  * This function is useful for fluid layout managers, like #ClutterBinLayout
13885  * or #ClutterTableLayout
13886  *
13887  * Since: 1.4
13888  */
13889 void
13890 clutter_actor_allocate_align_fill (ClutterActor           *self,
13891                                    const ClutterActorBox  *box,
13892                                    gdouble                 x_align,
13893                                    gdouble                 y_align,
13894                                    gboolean                x_fill,
13895                                    gboolean                y_fill,
13896                                    ClutterAllocationFlags  flags)
13897 {
13898   ClutterActorPrivate *priv;
13899   ClutterActorBox allocation = { 0, };
13900   gfloat x_offset, y_offset;
13901   gfloat available_width, available_height;
13902   gfloat child_width, child_height;
13903
13904   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13905   g_return_if_fail (box != NULL);
13906   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13907   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13908
13909   priv = self->priv;
13910
13911   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13912   clutter_actor_box_get_size (box, &available_width, &available_height);
13913
13914   if (available_width < 0)
13915     available_width = 0;
13916
13917   if (available_height < 0)
13918     available_height = 0;
13919
13920   if (x_fill)
13921     {
13922       allocation.x1 = x_offset;
13923       allocation.x2 = allocation.x1 + available_width;
13924     }
13925
13926   if (y_fill)
13927     {
13928       allocation.y1 = y_offset;
13929       allocation.y2 = allocation.y1 + available_height;
13930     }
13931
13932   /* if we are filling horizontally and vertically then we're done */
13933   if (x_fill && y_fill)
13934     goto out;
13935
13936   child_width = child_height = 0.0f;
13937
13938   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13939     {
13940       gfloat min_width, natural_width;
13941       gfloat min_height, natural_height;
13942
13943       clutter_actor_get_preferred_width (self, available_height,
13944                                          &min_width,
13945                                          &natural_width);
13946
13947       child_width = CLAMP (natural_width, min_width, available_width);
13948
13949       if (!y_fill)
13950         {
13951           clutter_actor_get_preferred_height (self, child_width,
13952                                               &min_height,
13953                                               &natural_height);
13954
13955           child_height = CLAMP (natural_height, min_height, available_height);
13956         }
13957     }
13958   else
13959     {
13960       gfloat min_width, natural_width;
13961       gfloat min_height, natural_height;
13962
13963       clutter_actor_get_preferred_height (self, available_width,
13964                                           &min_height,
13965                                           &natural_height);
13966
13967       child_height = CLAMP (natural_height, min_height, available_height);
13968
13969       if (!x_fill)
13970         {
13971           clutter_actor_get_preferred_width (self, child_height,
13972                                              &min_width,
13973                                              &natural_width);
13974
13975           child_width = CLAMP (natural_width, min_width, available_width);
13976         }
13977     }
13978
13979   /* invert the horizontal alignment for RTL languages */
13980   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13981     x_align = 1.0 - x_align;
13982
13983   if (!x_fill)
13984     {
13985       allocation.x1 = x_offset
13986                     + ((available_width - child_width) * x_align);
13987       allocation.x2 = allocation.x1 + child_width;
13988     }
13989
13990   if (!y_fill)
13991     {
13992       allocation.y1 = y_offset
13993                     + ((available_height - child_height) * y_align);
13994       allocation.y2 = allocation.y1 + child_height;
13995     }
13996
13997 out:
13998   clutter_actor_box_clamp_to_pixel (&allocation);
13999   clutter_actor_allocate (self, &allocation, flags);
14000 }
14001
14002 /**
14003  * clutter_actor_grab_key_focus:
14004  * @self: a #ClutterActor
14005  *
14006  * Sets the key focus of the #ClutterStage including @self
14007  * to this #ClutterActor.
14008  *
14009  * Since: 1.0
14010  */
14011 void
14012 clutter_actor_grab_key_focus (ClutterActor *self)
14013 {
14014   ClutterActor *stage;
14015
14016   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14017
14018   stage = _clutter_actor_get_stage_internal (self);
14019   if (stage != NULL)
14020     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
14021 }
14022
14023 /**
14024  * clutter_actor_get_pango_context:
14025  * @self: a #ClutterActor
14026  *
14027  * Retrieves the #PangoContext for @self. The actor's #PangoContext
14028  * is already configured using the appropriate font map, resolution
14029  * and font options.
14030  *
14031  * Unlike clutter_actor_create_pango_context(), this context is owend
14032  * by the #ClutterActor and it will be updated each time the options
14033  * stored by the #ClutterBackend change.
14034  *
14035  * You can use the returned #PangoContext to create a #PangoLayout
14036  * and render text using cogl_pango_render_layout() to reuse the
14037  * glyphs cache also used by Clutter.
14038  *
14039  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
14040  *   The returned #PangoContext is owned by the actor and should not be
14041  *   unreferenced by the application code
14042  *
14043  * Since: 1.0
14044  */
14045 PangoContext *
14046 clutter_actor_get_pango_context (ClutterActor *self)
14047 {
14048   ClutterActorPrivate *priv;
14049
14050   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14051
14052   priv = self->priv;
14053
14054   if (priv->pango_context != NULL)
14055     return priv->pango_context;
14056
14057   priv->pango_context = _clutter_context_get_pango_context ();
14058   g_object_ref (priv->pango_context);
14059
14060   return priv->pango_context;
14061 }
14062
14063 /**
14064  * clutter_actor_create_pango_context:
14065  * @self: a #ClutterActor
14066  *
14067  * Creates a #PangoContext for the given actor. The #PangoContext
14068  * is already configured using the appropriate font map, resolution
14069  * and font options.
14070  *
14071  * See also clutter_actor_get_pango_context().
14072  *
14073  * Return value: (transfer full): the newly created #PangoContext.
14074  *   Use g_object_unref() on the returned value to deallocate its
14075  *   resources
14076  *
14077  * Since: 1.0
14078  */
14079 PangoContext *
14080 clutter_actor_create_pango_context (ClutterActor *self)
14081 {
14082   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14083
14084   return _clutter_context_create_pango_context ();
14085 }
14086
14087 /**
14088  * clutter_actor_create_pango_layout:
14089  * @self: a #ClutterActor
14090  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14091  *
14092  * Creates a new #PangoLayout from the same #PangoContext used
14093  * by the #ClutterActor. The #PangoLayout is already configured
14094  * with the font map, resolution and font options, and the
14095  * given @text.
14096  *
14097  * If you want to keep around a #PangoLayout created by this
14098  * function you will have to connect to the #ClutterBackend::font-changed
14099  * and #ClutterBackend::resolution-changed signals, and call
14100  * pango_layout_context_changed() in response to them.
14101  *
14102  * Return value: (transfer full): the newly created #PangoLayout.
14103  *   Use g_object_unref() when done
14104  *
14105  * Since: 1.0
14106  */
14107 PangoLayout *
14108 clutter_actor_create_pango_layout (ClutterActor *self,
14109                                    const gchar  *text)
14110 {
14111   PangoContext *context;
14112   PangoLayout *layout;
14113
14114   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14115
14116   context = clutter_actor_get_pango_context (self);
14117   layout = pango_layout_new (context);
14118
14119   if (text)
14120     pango_layout_set_text (layout, text, -1);
14121
14122   return layout;
14123 }
14124
14125 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14126  * ClutterOffscreenEffect.
14127  */
14128 void
14129 _clutter_actor_set_opacity_override (ClutterActor *self,
14130                                      gint          opacity)
14131 {
14132   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14133
14134   self->priv->opacity_override = opacity;
14135 }
14136
14137 gint
14138 _clutter_actor_get_opacity_override (ClutterActor *self)
14139 {
14140   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14141
14142   return self->priv->opacity_override;
14143 }
14144
14145 /* Allows you to disable applying the actors model view transform during
14146  * a paint. Used by ClutterClone. */
14147 void
14148 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14149                                                 gboolean      enable)
14150 {
14151   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14152
14153   self->priv->enable_model_view_transform = enable;
14154 }
14155
14156 void
14157 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14158                                           gboolean      enable)
14159 {
14160   ClutterActorPrivate *priv;
14161
14162   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14163
14164   priv = self->priv;
14165
14166   priv->enable_paint_unmapped = enable;
14167
14168   if (priv->enable_paint_unmapped)
14169     {
14170       /* Make sure that the parents of the widget are realized first;
14171        * otherwise checks in clutter_actor_update_map_state() will
14172        * fail.
14173        */
14174       clutter_actor_realize (self);
14175
14176       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14177     }
14178   else
14179     {
14180       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14181     }
14182 }
14183
14184 static void
14185 clutter_anchor_coord_get_units (ClutterActor      *self,
14186                                 const AnchorCoord *coord,
14187                                 gfloat            *x,
14188                                 gfloat            *y,
14189                                 gfloat            *z)
14190 {
14191   if (coord->is_fractional)
14192     {
14193       gfloat actor_width, actor_height;
14194
14195       clutter_actor_get_size (self, &actor_width, &actor_height);
14196
14197       if (x)
14198         *x = actor_width * coord->v.fraction.x;
14199
14200       if (y)
14201         *y = actor_height * coord->v.fraction.y;
14202
14203       if (z)
14204         *z = 0;
14205     }
14206   else
14207     {
14208       if (x)
14209         *x = coord->v.units.x;
14210
14211       if (y)
14212         *y = coord->v.units.y;
14213
14214       if (z)
14215         *z = coord->v.units.z;
14216     }
14217 }
14218
14219 static void
14220 clutter_anchor_coord_set_units (AnchorCoord *coord,
14221                                 gfloat       x,
14222                                 gfloat       y,
14223                                 gfloat       z)
14224 {
14225   coord->is_fractional = FALSE;
14226   coord->v.units.x = x;
14227   coord->v.units.y = y;
14228   coord->v.units.z = z;
14229 }
14230
14231 static ClutterGravity
14232 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14233 {
14234   if (coord->is_fractional)
14235     {
14236       if (coord->v.fraction.x == 0.0)
14237         {
14238           if (coord->v.fraction.y == 0.0)
14239             return CLUTTER_GRAVITY_NORTH_WEST;
14240           else if (coord->v.fraction.y == 0.5)
14241             return CLUTTER_GRAVITY_WEST;
14242           else if (coord->v.fraction.y == 1.0)
14243             return CLUTTER_GRAVITY_SOUTH_WEST;
14244           else
14245             return CLUTTER_GRAVITY_NONE;
14246         }
14247       else if (coord->v.fraction.x == 0.5)
14248         {
14249           if (coord->v.fraction.y == 0.0)
14250             return CLUTTER_GRAVITY_NORTH;
14251           else if (coord->v.fraction.y == 0.5)
14252             return CLUTTER_GRAVITY_CENTER;
14253           else if (coord->v.fraction.y == 1.0)
14254             return CLUTTER_GRAVITY_SOUTH;
14255           else
14256             return CLUTTER_GRAVITY_NONE;
14257         }
14258       else if (coord->v.fraction.x == 1.0)
14259         {
14260           if (coord->v.fraction.y == 0.0)
14261             return CLUTTER_GRAVITY_NORTH_EAST;
14262           else if (coord->v.fraction.y == 0.5)
14263             return CLUTTER_GRAVITY_EAST;
14264           else if (coord->v.fraction.y == 1.0)
14265             return CLUTTER_GRAVITY_SOUTH_EAST;
14266           else
14267             return CLUTTER_GRAVITY_NONE;
14268         }
14269       else
14270         return CLUTTER_GRAVITY_NONE;
14271     }
14272   else
14273     return CLUTTER_GRAVITY_NONE;
14274 }
14275
14276 static void
14277 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14278                                   ClutterGravity  gravity)
14279 {
14280   switch (gravity)
14281     {
14282     case CLUTTER_GRAVITY_NORTH:
14283       coord->v.fraction.x = 0.5;
14284       coord->v.fraction.y = 0.0;
14285       break;
14286
14287     case CLUTTER_GRAVITY_NORTH_EAST:
14288       coord->v.fraction.x = 1.0;
14289       coord->v.fraction.y = 0.0;
14290       break;
14291
14292     case CLUTTER_GRAVITY_EAST:
14293       coord->v.fraction.x = 1.0;
14294       coord->v.fraction.y = 0.5;
14295       break;
14296
14297     case CLUTTER_GRAVITY_SOUTH_EAST:
14298       coord->v.fraction.x = 1.0;
14299       coord->v.fraction.y = 1.0;
14300       break;
14301
14302     case CLUTTER_GRAVITY_SOUTH:
14303       coord->v.fraction.x = 0.5;
14304       coord->v.fraction.y = 1.0;
14305       break;
14306
14307     case CLUTTER_GRAVITY_SOUTH_WEST:
14308       coord->v.fraction.x = 0.0;
14309       coord->v.fraction.y = 1.0;
14310       break;
14311
14312     case CLUTTER_GRAVITY_WEST:
14313       coord->v.fraction.x = 0.0;
14314       coord->v.fraction.y = 0.5;
14315       break;
14316
14317     case CLUTTER_GRAVITY_NORTH_WEST:
14318       coord->v.fraction.x = 0.0;
14319       coord->v.fraction.y = 0.0;
14320       break;
14321
14322     case CLUTTER_GRAVITY_CENTER:
14323       coord->v.fraction.x = 0.5;
14324       coord->v.fraction.y = 0.5;
14325       break;
14326
14327     default:
14328       coord->v.fraction.x = 0.0;
14329       coord->v.fraction.y = 0.0;
14330       break;
14331     }
14332
14333   coord->is_fractional = TRUE;
14334 }
14335
14336 static gboolean
14337 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14338 {
14339   if (coord->is_fractional)
14340     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14341   else
14342     return (coord->v.units.x == 0.0
14343             && coord->v.units.y == 0.0
14344             && coord->v.units.z == 0.0);
14345 }
14346
14347 /**
14348  * clutter_actor_get_flags:
14349  * @self: a #ClutterActor
14350  *
14351  * Retrieves the flags set on @self
14352  *
14353  * Return value: a bitwise or of #ClutterActorFlags or 0
14354  *
14355  * Since: 1.0
14356  */
14357 ClutterActorFlags
14358 clutter_actor_get_flags (ClutterActor *self)
14359 {
14360   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14361
14362   return self->flags;
14363 }
14364
14365 /**
14366  * clutter_actor_set_flags:
14367  * @self: a #ClutterActor
14368  * @flags: the flags to set
14369  *
14370  * Sets @flags on @self
14371  *
14372  * This function will emit notifications for the changed properties
14373  *
14374  * Since: 1.0
14375  */
14376 void
14377 clutter_actor_set_flags (ClutterActor      *self,
14378                          ClutterActorFlags  flags)
14379 {
14380   ClutterActorFlags old_flags;
14381   GObject *obj;
14382   gboolean was_reactive_set, reactive_set;
14383   gboolean was_realized_set, realized_set;
14384   gboolean was_mapped_set, mapped_set;
14385   gboolean was_visible_set, visible_set;
14386
14387   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14388
14389   if (self->flags == flags)
14390     return;
14391
14392   obj = G_OBJECT (self);
14393   g_object_ref (obj);
14394   g_object_freeze_notify (obj);
14395
14396   old_flags = self->flags;
14397
14398   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14399   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14400   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14401   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14402
14403   self->flags |= flags;
14404
14405   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14406   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14407   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14408   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14409
14410   if (reactive_set != was_reactive_set)
14411     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14412
14413   if (realized_set != was_realized_set)
14414     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14415
14416   if (mapped_set != was_mapped_set)
14417     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14418
14419   if (visible_set != was_visible_set)
14420     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14421
14422   g_object_thaw_notify (obj);
14423   g_object_unref (obj);
14424 }
14425
14426 /**
14427  * clutter_actor_unset_flags:
14428  * @self: a #ClutterActor
14429  * @flags: the flags to unset
14430  *
14431  * Unsets @flags on @self
14432  *
14433  * This function will emit notifications for the changed properties
14434  *
14435  * Since: 1.0
14436  */
14437 void
14438 clutter_actor_unset_flags (ClutterActor      *self,
14439                            ClutterActorFlags  flags)
14440 {
14441   ClutterActorFlags old_flags;
14442   GObject *obj;
14443   gboolean was_reactive_set, reactive_set;
14444   gboolean was_realized_set, realized_set;
14445   gboolean was_mapped_set, mapped_set;
14446   gboolean was_visible_set, visible_set;
14447
14448   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14449
14450   obj = G_OBJECT (self);
14451   g_object_freeze_notify (obj);
14452
14453   old_flags = self->flags;
14454
14455   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14456   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14457   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14458   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14459
14460   self->flags &= ~flags;
14461
14462   if (self->flags == old_flags)
14463     return;
14464
14465   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14466   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14467   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14468   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14469
14470   if (reactive_set != was_reactive_set)
14471     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14472
14473   if (realized_set != was_realized_set)
14474     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14475
14476   if (mapped_set != was_mapped_set)
14477     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14478
14479   if (visible_set != was_visible_set)
14480     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14481
14482   g_object_thaw_notify (obj);
14483 }
14484
14485 /**
14486  * clutter_actor_get_transformation_matrix:
14487  * @self: a #ClutterActor
14488  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14489  *
14490  * Retrieves the transformations applied to @self relative to its
14491  * parent.
14492  *
14493  * Since: 1.0
14494  */
14495 void
14496 clutter_actor_get_transformation_matrix (ClutterActor *self,
14497                                          CoglMatrix   *matrix)
14498 {
14499   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14500
14501   cogl_matrix_init_identity (matrix);
14502
14503   _clutter_actor_apply_modelview_transform (self, matrix);
14504 }
14505
14506 void
14507 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14508                                    gboolean      is_in_clone_paint)
14509 {
14510   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14511   self->priv->in_clone_paint = is_in_clone_paint;
14512 }
14513
14514 /**
14515  * clutter_actor_is_in_clone_paint:
14516  * @self: a #ClutterActor
14517  *
14518  * Checks whether @self is being currently painted by a #ClutterClone
14519  *
14520  * This function is useful only inside the ::paint virtual function
14521  * implementations or within handlers for the #ClutterActor::paint
14522  * signal
14523  *
14524  * This function should not be used by applications
14525  *
14526  * Return value: %TRUE if the #ClutterActor is currently being painted
14527  *   by a #ClutterClone, and %FALSE otherwise
14528  *
14529  * Since: 1.0
14530  */
14531 gboolean
14532 clutter_actor_is_in_clone_paint (ClutterActor *self)
14533 {
14534   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14535
14536   return self->priv->in_clone_paint;
14537 }
14538
14539 static gboolean
14540 set_direction_recursive (ClutterActor *actor,
14541                          gpointer      user_data)
14542 {
14543   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14544
14545   clutter_actor_set_text_direction (actor, text_dir);
14546
14547   return TRUE;
14548 }
14549
14550 /**
14551  * clutter_actor_set_text_direction:
14552  * @self: a #ClutterActor
14553  * @text_dir: the text direction for @self
14554  *
14555  * Sets the #ClutterTextDirection for an actor
14556  *
14557  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14558  *
14559  * If @self implements #ClutterContainer then this function will recurse
14560  * inside all the children of @self (including the internal ones).
14561  *
14562  * Composite actors not implementing #ClutterContainer, or actors requiring
14563  * special handling when the text direction changes, should connect to
14564  * the #GObject::notify signal for the #ClutterActor:text-direction property
14565  *
14566  * Since: 1.2
14567  */
14568 void
14569 clutter_actor_set_text_direction (ClutterActor         *self,
14570                                   ClutterTextDirection  text_dir)
14571 {
14572   ClutterActorPrivate *priv;
14573
14574   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14575   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14576
14577   priv = self->priv;
14578
14579   if (priv->text_direction != text_dir)
14580     {
14581       priv->text_direction = text_dir;
14582
14583       /* we need to emit the notify::text-direction first, so that
14584        * the sub-classes can catch that and do specific handling of
14585        * the text direction; see clutter_text_direction_changed_cb()
14586        * inside clutter-text.c
14587        */
14588       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14589
14590       _clutter_actor_foreach_child (self, set_direction_recursive,
14591                                     GINT_TO_POINTER (text_dir));
14592
14593       clutter_actor_queue_relayout (self);
14594     }
14595 }
14596
14597 void
14598 _clutter_actor_set_has_pointer (ClutterActor *self,
14599                                 gboolean      has_pointer)
14600 {
14601   ClutterActorPrivate *priv = self->priv;
14602
14603   if (priv->has_pointer != has_pointer)
14604     {
14605       priv->has_pointer = has_pointer;
14606
14607       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14608     }
14609 }
14610
14611 /**
14612  * clutter_actor_get_text_direction:
14613  * @self: a #ClutterActor
14614  *
14615  * Retrieves the value set using clutter_actor_set_text_direction()
14616  *
14617  * If no text direction has been previously set, the default text
14618  * direction, as returned by clutter_get_default_text_direction(), will
14619  * be returned instead
14620  *
14621  * Return value: the #ClutterTextDirection for the actor
14622  *
14623  * Since: 1.2
14624  */
14625 ClutterTextDirection
14626 clutter_actor_get_text_direction (ClutterActor *self)
14627 {
14628   ClutterActorPrivate *priv;
14629
14630   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14631                         CLUTTER_TEXT_DIRECTION_LTR);
14632
14633   priv = self->priv;
14634
14635   /* if no direction has been set yet use the default */
14636   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14637     priv->text_direction = clutter_get_default_text_direction ();
14638
14639   return priv->text_direction;
14640 }
14641
14642 /**
14643  * clutter_actor_push_internal:
14644  * @self: a #ClutterActor
14645  *
14646  * Should be used by actors implementing the #ClutterContainer and with
14647  * internal children added through clutter_actor_set_parent(), for instance:
14648  *
14649  * |[
14650  *   static void
14651  *   my_actor_init (MyActor *self)
14652  *   {
14653  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14654  *
14655  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14656  *
14657  *     /&ast; calling clutter_actor_set_parent() now will result in
14658  *      &ast; the internal flag being set on a child of MyActor
14659  *      &ast;/
14660  *
14661  *     /&ast; internal child - a background texture &ast;/
14662  *     self->priv->background_tex = clutter_texture_new ();
14663  *     clutter_actor_set_parent (self->priv->background_tex,
14664  *                               CLUTTER_ACTOR (self));
14665  *
14666  *     /&ast; internal child - a label &ast;/
14667  *     self->priv->label = clutter_text_new ();
14668  *     clutter_actor_set_parent (self->priv->label,
14669  *                               CLUTTER_ACTOR (self));
14670  *
14671  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14672  *
14673  *     /&ast; calling clutter_actor_set_parent() now will not result in
14674  *      &ast; the internal flag being set on a child of MyActor
14675  *      &ast;/
14676  *   }
14677  * ]|
14678  *
14679  * This function will be used by Clutter to toggle an "internal child"
14680  * flag whenever clutter_actor_set_parent() is called; internal children
14681  * are handled differently by Clutter, specifically when destroying their
14682  * parent.
14683  *
14684  * Call clutter_actor_pop_internal() when you finished adding internal
14685  * children.
14686  *
14687  * Nested calls to clutter_actor_push_internal() are allowed, but each
14688  * one must by followed by a clutter_actor_pop_internal() call.
14689  *
14690  * Since: 1.2
14691  *
14692  * Deprecated: 1.10: All children of an actor are accessible through
14693  *   the #ClutterActor API, and #ClutterActor implements the
14694  *   #ClutterContainer interface, so this function is only useful
14695  *   for legacy containers overriding the default implementation.
14696  */
14697 void
14698 clutter_actor_push_internal (ClutterActor *self)
14699 {
14700   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14701
14702   self->priv->internal_child += 1;
14703 }
14704
14705 /**
14706  * clutter_actor_pop_internal:
14707  * @self: a #ClutterActor
14708  *
14709  * Disables the effects of clutter_actor_push_internal().
14710  *
14711  * Since: 1.2
14712  *
14713  * Deprecated: 1.10: All children of an actor are accessible through
14714  *   the #ClutterActor API. This function is only useful for legacy
14715  *   containers overriding the default implementation of the
14716  *   #ClutterContainer interface.
14717  */
14718 void
14719 clutter_actor_pop_internal (ClutterActor *self)
14720 {
14721   ClutterActorPrivate *priv;
14722
14723   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14724
14725   priv = self->priv;
14726
14727   if (priv->internal_child == 0)
14728     {
14729       g_warning ("Mismatched %s: you need to call "
14730                  "clutter_actor_push_composite() at least once before "
14731                  "calling this function", G_STRFUNC);
14732       return;
14733     }
14734
14735   priv->internal_child -= 1;
14736 }
14737
14738 /**
14739  * clutter_actor_has_pointer:
14740  * @self: a #ClutterActor
14741  *
14742  * Checks whether an actor contains the pointer of a
14743  * #ClutterInputDevice
14744  *
14745  * Return value: %TRUE if the actor contains the pointer, and
14746  *   %FALSE otherwise
14747  *
14748  * Since: 1.2
14749  */
14750 gboolean
14751 clutter_actor_has_pointer (ClutterActor *self)
14752 {
14753   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14754
14755   return self->priv->has_pointer;
14756 }
14757
14758 /* XXX: This is a workaround for not being able to break the ABI of
14759  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14760  * clutter_actor_queue_clipped_redraw() for details.
14761  */
14762 ClutterPaintVolume *
14763 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14764 {
14765   return g_object_get_data (G_OBJECT (self),
14766                             "-clutter-actor-queue-redraw-clip");
14767 }
14768
14769 void
14770 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14771                                       ClutterPaintVolume *clip)
14772 {
14773   g_object_set_data (G_OBJECT (self),
14774                      "-clutter-actor-queue-redraw-clip",
14775                      clip);
14776 }
14777
14778 /**
14779  * clutter_actor_has_allocation:
14780  * @self: a #ClutterActor
14781  *
14782  * Checks if the actor has an up-to-date allocation assigned to
14783  * it. This means that the actor should have an allocation: it's
14784  * visible and has a parent. It also means that there is no
14785  * outstanding relayout request in progress for the actor or its
14786  * children (There might be other outstanding layout requests in
14787  * progress that will cause the actor to get a new allocation
14788  * when the stage is laid out, however).
14789  *
14790  * If this function returns %FALSE, then the actor will normally
14791  * be allocated before it is next drawn on the screen.
14792  *
14793  * Return value: %TRUE if the actor has an up-to-date allocation
14794  *
14795  * Since: 1.4
14796  */
14797 gboolean
14798 clutter_actor_has_allocation (ClutterActor *self)
14799 {
14800   ClutterActorPrivate *priv;
14801
14802   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14803
14804   priv = self->priv;
14805
14806   return priv->parent != NULL &&
14807          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14808          !priv->needs_allocation;
14809 }
14810
14811 /**
14812  * clutter_actor_add_action:
14813  * @self: a #ClutterActor
14814  * @action: a #ClutterAction
14815  *
14816  * Adds @action to the list of actions applied to @self
14817  *
14818  * A #ClutterAction can only belong to one actor at a time
14819  *
14820  * The #ClutterActor will hold a reference on @action until either
14821  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14822  * is called
14823  *
14824  * Since: 1.4
14825  */
14826 void
14827 clutter_actor_add_action (ClutterActor  *self,
14828                           ClutterAction *action)
14829 {
14830   ClutterActorPrivate *priv;
14831
14832   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14833   g_return_if_fail (CLUTTER_IS_ACTION (action));
14834
14835   priv = self->priv;
14836
14837   if (priv->actions == NULL)
14838     {
14839       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14840       priv->actions->actor = self;
14841     }
14842
14843   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14844
14845   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14846 }
14847
14848 /**
14849  * clutter_actor_add_action_with_name:
14850  * @self: a #ClutterActor
14851  * @name: the name to set on the action
14852  * @action: a #ClutterAction
14853  *
14854  * A convenience function for setting the name of a #ClutterAction
14855  * while adding it to the list of actions applied to @self
14856  *
14857  * This function is the logical equivalent of:
14858  *
14859  * |[
14860  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14861  *   clutter_actor_add_action (self, action);
14862  * ]|
14863  *
14864  * Since: 1.4
14865  */
14866 void
14867 clutter_actor_add_action_with_name (ClutterActor  *self,
14868                                     const gchar   *name,
14869                                     ClutterAction *action)
14870 {
14871   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14872   g_return_if_fail (name != NULL);
14873   g_return_if_fail (CLUTTER_IS_ACTION (action));
14874
14875   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14876   clutter_actor_add_action (self, action);
14877 }
14878
14879 /**
14880  * clutter_actor_remove_action:
14881  * @self: a #ClutterActor
14882  * @action: a #ClutterAction
14883  *
14884  * Removes @action from the list of actions applied to @self
14885  *
14886  * The reference held by @self on the #ClutterAction will be released
14887  *
14888  * Since: 1.4
14889  */
14890 void
14891 clutter_actor_remove_action (ClutterActor  *self,
14892                              ClutterAction *action)
14893 {
14894   ClutterActorPrivate *priv;
14895
14896   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14897   g_return_if_fail (CLUTTER_IS_ACTION (action));
14898
14899   priv = self->priv;
14900
14901   if (priv->actions == NULL)
14902     return;
14903
14904   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14905
14906   if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
14907     g_clear_object (&priv->actions);
14908
14909   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14910 }
14911
14912 /**
14913  * clutter_actor_remove_action_by_name:
14914  * @self: a #ClutterActor
14915  * @name: the name of the action to remove
14916  *
14917  * Removes the #ClutterAction with the given name from the list
14918  * of actions applied to @self
14919  *
14920  * Since: 1.4
14921  */
14922 void
14923 clutter_actor_remove_action_by_name (ClutterActor *self,
14924                                      const gchar  *name)
14925 {
14926   ClutterActorPrivate *priv;
14927   ClutterActorMeta *meta;
14928
14929   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14930   g_return_if_fail (name != NULL);
14931
14932   priv = self->priv;
14933
14934   if (priv->actions == NULL)
14935     return;
14936
14937   meta = _clutter_meta_group_get_meta (priv->actions, name);
14938   if (meta == NULL)
14939     return;
14940
14941   _clutter_meta_group_remove_meta (priv->actions, meta);
14942
14943   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14944 }
14945
14946 /**
14947  * clutter_actor_get_actions:
14948  * @self: a #ClutterActor
14949  *
14950  * Retrieves the list of actions applied to @self
14951  *
14952  * Return value: (transfer container) (element-type Clutter.Action): a copy
14953  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14954  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14955  *   allocated by the returned #GList
14956  *
14957  * Since: 1.4
14958  */
14959 GList *
14960 clutter_actor_get_actions (ClutterActor *self)
14961 {
14962   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14963
14964   if (self->priv->actions == NULL)
14965     return NULL;
14966
14967   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14968 }
14969
14970 /**
14971  * clutter_actor_get_action:
14972  * @self: a #ClutterActor
14973  * @name: the name of the action to retrieve
14974  *
14975  * Retrieves the #ClutterAction with the given name in the list
14976  * of actions applied to @self
14977  *
14978  * Return value: (transfer none): a #ClutterAction for the given
14979  *   name, or %NULL. The returned #ClutterAction is owned by the
14980  *   actor and it should not be unreferenced directly
14981  *
14982  * Since: 1.4
14983  */
14984 ClutterAction *
14985 clutter_actor_get_action (ClutterActor *self,
14986                           const gchar  *name)
14987 {
14988   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14989   g_return_val_if_fail (name != NULL, NULL);
14990
14991   if (self->priv->actions == NULL)
14992     return NULL;
14993
14994   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14995 }
14996
14997 /**
14998  * clutter_actor_clear_actions:
14999  * @self: a #ClutterActor
15000  *
15001  * Clears the list of actions applied to @self
15002  *
15003  * Since: 1.4
15004  */
15005 void
15006 clutter_actor_clear_actions (ClutterActor *self)
15007 {
15008   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15009
15010   if (self->priv->actions == NULL)
15011     return;
15012
15013   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
15014 }
15015
15016 /**
15017  * clutter_actor_add_constraint:
15018  * @self: a #ClutterActor
15019  * @constraint: a #ClutterConstraint
15020  *
15021  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
15022  * to @self
15023  *
15024  * The #ClutterActor will hold a reference on the @constraint until
15025  * either clutter_actor_remove_constraint() or
15026  * clutter_actor_clear_constraints() is called.
15027  *
15028  * Since: 1.4
15029  */
15030 void
15031 clutter_actor_add_constraint (ClutterActor      *self,
15032                               ClutterConstraint *constraint)
15033 {
15034   ClutterActorPrivate *priv;
15035
15036   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15037   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15038
15039   priv = self->priv;
15040
15041   if (priv->constraints == NULL)
15042     {
15043       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15044       priv->constraints->actor = self;
15045     }
15046
15047   _clutter_meta_group_add_meta (priv->constraints,
15048                                 CLUTTER_ACTOR_META (constraint));
15049   clutter_actor_queue_relayout (self);
15050
15051   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15052 }
15053
15054 /**
15055  * clutter_actor_add_constraint_with_name:
15056  * @self: a #ClutterActor
15057  * @name: the name to set on the constraint
15058  * @constraint: a #ClutterConstraint
15059  *
15060  * A convenience function for setting the name of a #ClutterConstraint
15061  * while adding it to the list of constraints applied to @self
15062  *
15063  * This function is the logical equivalent of:
15064  *
15065  * |[
15066  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15067  *   clutter_actor_add_constraint (self, constraint);
15068  * ]|
15069  *
15070  * Since: 1.4
15071  */
15072 void
15073 clutter_actor_add_constraint_with_name (ClutterActor      *self,
15074                                         const gchar       *name,
15075                                         ClutterConstraint *constraint)
15076 {
15077   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15078   g_return_if_fail (name != NULL);
15079   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15080
15081   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15082   clutter_actor_add_constraint (self, constraint);
15083 }
15084
15085 /**
15086  * clutter_actor_remove_constraint:
15087  * @self: a #ClutterActor
15088  * @constraint: a #ClutterConstraint
15089  *
15090  * Removes @constraint from the list of constraints applied to @self
15091  *
15092  * The reference held by @self on the #ClutterConstraint will be released
15093  *
15094  * Since: 1.4
15095  */
15096 void
15097 clutter_actor_remove_constraint (ClutterActor      *self,
15098                                  ClutterConstraint *constraint)
15099 {
15100   ClutterActorPrivate *priv;
15101
15102   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15103   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15104
15105   priv = self->priv;
15106
15107   if (priv->constraints == NULL)
15108     return;
15109
15110   _clutter_meta_group_remove_meta (priv->constraints,
15111                                    CLUTTER_ACTOR_META (constraint));
15112
15113   if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15114     g_clear_object (&priv->constraints);
15115
15116   clutter_actor_queue_relayout (self);
15117
15118   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15119 }
15120
15121 /**
15122  * clutter_actor_remove_constraint_by_name:
15123  * @self: a #ClutterActor
15124  * @name: the name of the constraint to remove
15125  *
15126  * Removes the #ClutterConstraint with the given name from the list
15127  * of constraints applied to @self
15128  *
15129  * Since: 1.4
15130  */
15131 void
15132 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15133                                          const gchar  *name)
15134 {
15135   ClutterActorPrivate *priv;
15136   ClutterActorMeta *meta;
15137
15138   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15139   g_return_if_fail (name != NULL);
15140
15141   priv = self->priv;
15142
15143   if (priv->constraints == NULL)
15144     return;
15145
15146   meta = _clutter_meta_group_get_meta (priv->constraints, name);
15147   if (meta == NULL)
15148     return;
15149
15150   _clutter_meta_group_remove_meta (priv->constraints, meta);
15151   clutter_actor_queue_relayout (self);
15152 }
15153
15154 /**
15155  * clutter_actor_get_constraints:
15156  * @self: a #ClutterActor
15157  *
15158  * Retrieves the list of constraints applied to @self
15159  *
15160  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15161  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15162  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15163  *   allocated by the returned #GList
15164  *
15165  * Since: 1.4
15166  */
15167 GList *
15168 clutter_actor_get_constraints (ClutterActor *self)
15169 {
15170   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15171
15172   if (self->priv->constraints == NULL)
15173     return NULL;
15174
15175   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15176 }
15177
15178 /**
15179  * clutter_actor_get_constraint:
15180  * @self: a #ClutterActor
15181  * @name: the name of the constraint to retrieve
15182  *
15183  * Retrieves the #ClutterConstraint with the given name in the list
15184  * of constraints applied to @self
15185  *
15186  * Return value: (transfer none): a #ClutterConstraint for the given
15187  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15188  *   actor and it should not be unreferenced directly
15189  *
15190  * Since: 1.4
15191  */
15192 ClutterConstraint *
15193 clutter_actor_get_constraint (ClutterActor *self,
15194                               const gchar  *name)
15195 {
15196   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15197   g_return_val_if_fail (name != NULL, NULL);
15198
15199   if (self->priv->constraints == NULL)
15200     return NULL;
15201
15202   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15203 }
15204
15205 /**
15206  * clutter_actor_clear_constraints:
15207  * @self: a #ClutterActor
15208  *
15209  * Clears the list of constraints applied to @self
15210  *
15211  * Since: 1.4
15212  */
15213 void
15214 clutter_actor_clear_constraints (ClutterActor *self)
15215 {
15216   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15217
15218   if (self->priv->constraints == NULL)
15219     return;
15220
15221   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15222
15223   clutter_actor_queue_relayout (self);
15224 }
15225
15226 /**
15227  * clutter_actor_set_clip_to_allocation:
15228  * @self: a #ClutterActor
15229  * @clip_set: %TRUE to apply a clip tracking the allocation
15230  *
15231  * Sets whether @self should be clipped to the same size as its
15232  * allocation
15233  *
15234  * Since: 1.4
15235  */
15236 void
15237 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15238                                       gboolean      clip_set)
15239 {
15240   ClutterActorPrivate *priv;
15241
15242   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15243
15244   clip_set = !!clip_set;
15245
15246   priv = self->priv;
15247
15248   if (priv->clip_to_allocation != clip_set)
15249     {
15250       priv->clip_to_allocation = clip_set;
15251
15252       clutter_actor_queue_redraw (self);
15253
15254       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15255     }
15256 }
15257
15258 /**
15259  * clutter_actor_get_clip_to_allocation:
15260  * @self: a #ClutterActor
15261  *
15262  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15263  *
15264  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15265  *
15266  * Since: 1.4
15267  */
15268 gboolean
15269 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15270 {
15271   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15272
15273   return self->priv->clip_to_allocation;
15274 }
15275
15276 /**
15277  * clutter_actor_add_effect:
15278  * @self: a #ClutterActor
15279  * @effect: a #ClutterEffect
15280  *
15281  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15282  *
15283  * The #ClutterActor will hold a reference on the @effect until either
15284  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15285  * called.
15286  *
15287  * Since: 1.4
15288  */
15289 void
15290 clutter_actor_add_effect (ClutterActor  *self,
15291                           ClutterEffect *effect)
15292 {
15293   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15294   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15295
15296   _clutter_actor_add_effect_internal (self, effect);
15297
15298   clutter_actor_queue_redraw (self);
15299
15300   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15301 }
15302
15303 /**
15304  * clutter_actor_add_effect_with_name:
15305  * @self: a #ClutterActor
15306  * @name: the name to set on the effect
15307  * @effect: a #ClutterEffect
15308  *
15309  * A convenience function for setting the name of a #ClutterEffect
15310  * while adding it to the list of effectss applied to @self
15311  *
15312  * This function is the logical equivalent of:
15313  *
15314  * |[
15315  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15316  *   clutter_actor_add_effect (self, effect);
15317  * ]|
15318  *
15319  * Since: 1.4
15320  */
15321 void
15322 clutter_actor_add_effect_with_name (ClutterActor  *self,
15323                                     const gchar   *name,
15324                                     ClutterEffect *effect)
15325 {
15326   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15327   g_return_if_fail (name != NULL);
15328   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15329
15330   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15331   clutter_actor_add_effect (self, effect);
15332 }
15333
15334 /**
15335  * clutter_actor_remove_effect:
15336  * @self: a #ClutterActor
15337  * @effect: a #ClutterEffect
15338  *
15339  * Removes @effect from the list of effects applied to @self
15340  *
15341  * The reference held by @self on the #ClutterEffect will be released
15342  *
15343  * Since: 1.4
15344  */
15345 void
15346 clutter_actor_remove_effect (ClutterActor  *self,
15347                              ClutterEffect *effect)
15348 {
15349   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15350   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15351
15352   _clutter_actor_remove_effect_internal (self, effect);
15353
15354   clutter_actor_queue_redraw (self);
15355
15356   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15357 }
15358
15359 /**
15360  * clutter_actor_remove_effect_by_name:
15361  * @self: a #ClutterActor
15362  * @name: the name of the effect to remove
15363  *
15364  * Removes the #ClutterEffect with the given name from the list
15365  * of effects applied to @self
15366  *
15367  * Since: 1.4
15368  */
15369 void
15370 clutter_actor_remove_effect_by_name (ClutterActor *self,
15371                                      const gchar  *name)
15372 {
15373   ClutterActorPrivate *priv;
15374   ClutterActorMeta *meta;
15375
15376   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15377   g_return_if_fail (name != NULL);
15378
15379   priv = self->priv;
15380
15381   if (priv->effects == NULL)
15382     return;
15383
15384   meta = _clutter_meta_group_get_meta (priv->effects, name);
15385   if (meta == NULL)
15386     return;
15387
15388   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15389 }
15390
15391 /**
15392  * clutter_actor_get_effects:
15393  * @self: a #ClutterActor
15394  *
15395  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15396  *
15397  * Return value: (transfer container) (element-type Clutter.Effect): a list
15398  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15399  *   list are owned by Clutter and they should not be freed. You should
15400  *   free the returned list using g_list_free() when done
15401  *
15402  * Since: 1.4
15403  */
15404 GList *
15405 clutter_actor_get_effects (ClutterActor *self)
15406 {
15407   ClutterActorPrivate *priv;
15408
15409   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15410
15411   priv = self->priv;
15412
15413   if (priv->effects == NULL)
15414     return NULL;
15415
15416   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15417 }
15418
15419 /**
15420  * clutter_actor_get_effect:
15421  * @self: a #ClutterActor
15422  * @name: the name of the effect to retrieve
15423  *
15424  * Retrieves the #ClutterEffect with the given name in the list
15425  * of effects applied to @self
15426  *
15427  * Return value: (transfer none): a #ClutterEffect for the given
15428  *   name, or %NULL. The returned #ClutterEffect is owned by the
15429  *   actor and it should not be unreferenced directly
15430  *
15431  * Since: 1.4
15432  */
15433 ClutterEffect *
15434 clutter_actor_get_effect (ClutterActor *self,
15435                           const gchar  *name)
15436 {
15437   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15438   g_return_val_if_fail (name != NULL, NULL);
15439
15440   if (self->priv->effects == NULL)
15441     return NULL;
15442
15443   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15444 }
15445
15446 /**
15447  * clutter_actor_clear_effects:
15448  * @self: a #ClutterActor
15449  *
15450  * Clears the list of effects applied to @self
15451  *
15452  * Since: 1.4
15453  */
15454 void
15455 clutter_actor_clear_effects (ClutterActor *self)
15456 {
15457   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15458
15459   if (self->priv->effects == NULL)
15460     return;
15461
15462   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15463
15464   clutter_actor_queue_redraw (self);
15465 }
15466
15467 /**
15468  * clutter_actor_has_key_focus:
15469  * @self: a #ClutterActor
15470  *
15471  * Checks whether @self is the #ClutterActor that has key focus
15472  *
15473  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15474  *
15475  * Since: 1.4
15476  */
15477 gboolean
15478 clutter_actor_has_key_focus (ClutterActor *self)
15479 {
15480   ClutterActor *stage;
15481
15482   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15483
15484   stage = _clutter_actor_get_stage_internal (self);
15485   if (stage == NULL)
15486     return FALSE;
15487
15488   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15489 }
15490
15491 static gboolean
15492 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15493                                       ClutterPaintVolume *pv)
15494 {
15495   ClutterActorPrivate *priv = self->priv;
15496
15497   /* Actors are only expected to report a valid paint volume
15498    * while they have a valid allocation. */
15499   if (G_UNLIKELY (priv->needs_allocation))
15500     {
15501       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15502                     "Actor needs allocation",
15503                     _clutter_actor_get_debug_name (self));
15504       return FALSE;
15505     }
15506
15507   /* Check if there are any handlers connected to the paint
15508    * signal. If there are then all bets are off for what the paint
15509    * volume for this actor might possibly be!
15510    *
15511    * XXX: It's expected that this is going to end up being quite a
15512    * costly check to have to do here, but we haven't come up with
15513    * another solution that can reliably catch paint signal handlers at
15514    * the right time to either avoid artefacts due to invalid stage
15515    * clipping or due to incorrect culling.
15516    *
15517    * Previously we checked in clutter_actor_paint(), but at that time
15518    * we may already be using a stage clip that could be derived from
15519    * an invalid paint-volume. We used to try and handle that by
15520    * queuing a follow up, unclipped, redraw but still the previous
15521    * checking wasn't enough to catch invalid volumes involved in
15522    * culling (considering that containers may derive their volume from
15523    * children that haven't yet been painted)
15524    *
15525    * Longer term, improved solutions could be:
15526    * - Disallow painting in the paint signal, only allow using it
15527    *   for tracking when paints happen. We can add another API that
15528    *   allows monkey patching the paint of arbitrary actors but in a
15529    *   more controlled way and that also supports modifying the
15530    *   paint-volume.
15531    * - If we could be notified somehow when signal handlers are
15532    *   connected we wouldn't have to poll for handlers like this.
15533    */
15534   if (g_signal_has_handler_pending (self,
15535                                     actor_signals[PAINT],
15536                                     0,
15537                                     TRUE))
15538     {
15539       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15540                     "Actor has \"paint\" signal handlers",
15541                     _clutter_actor_get_debug_name (self));
15542       return FALSE;
15543     }
15544
15545   _clutter_paint_volume_init_static (pv, self);
15546
15547   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15548     {
15549       clutter_paint_volume_free (pv);
15550       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15551                     "Actor failed to report a volume",
15552                     _clutter_actor_get_debug_name (self));
15553       return FALSE;
15554     }
15555
15556   /* since effects can modify the paint volume, we allow them to actually
15557    * do this by making get_paint_volume() "context sensitive"
15558    */
15559   if (priv->effects != NULL)
15560     {
15561       if (priv->current_effect != NULL)
15562         {
15563           const GList *effects, *l;
15564
15565           /* if we are being called from within the paint sequence of
15566            * an actor, get the paint volume up to the current effect
15567            */
15568           effects = _clutter_meta_group_peek_metas (priv->effects);
15569           for (l = effects;
15570                l != NULL || (l != NULL && l->data != priv->current_effect);
15571                l = l->next)
15572             {
15573               if (!_clutter_effect_get_paint_volume (l->data, pv))
15574                 {
15575                   clutter_paint_volume_free (pv);
15576                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15577                                 "Effect (%s) failed to report a volume",
15578                                 _clutter_actor_get_debug_name (self),
15579                                 _clutter_actor_meta_get_debug_name (l->data));
15580                   return FALSE;
15581                 }
15582             }
15583         }
15584       else
15585         {
15586           const GList *effects, *l;
15587
15588           /* otherwise, get the cumulative volume */
15589           effects = _clutter_meta_group_peek_metas (priv->effects);
15590           for (l = effects; l != NULL; l = l->next)
15591             if (!_clutter_effect_get_paint_volume (l->data, pv))
15592               {
15593                 clutter_paint_volume_free (pv);
15594                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15595                               "Effect (%s) failed to report a volume",
15596                               _clutter_actor_get_debug_name (self),
15597                               _clutter_actor_meta_get_debug_name (l->data));
15598                 return FALSE;
15599               }
15600         }
15601     }
15602
15603   return TRUE;
15604 }
15605
15606 /* The public clutter_actor_get_paint_volume API returns a const
15607  * pointer since we return a pointer directly to the cached
15608  * PaintVolume associated with the actor and don't want the user to
15609  * inadvertently modify it, but for internal uses we sometimes need
15610  * access to the same PaintVolume but need to apply some book-keeping
15611  * modifications to it so we don't want a const pointer.
15612  */
15613 static ClutterPaintVolume *
15614 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15615 {
15616   ClutterActorPrivate *priv;
15617
15618   priv = self->priv;
15619
15620   if (priv->paint_volume_valid)
15621     clutter_paint_volume_free (&priv->paint_volume);
15622
15623   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15624     {
15625       priv->paint_volume_valid = TRUE;
15626       return &priv->paint_volume;
15627     }
15628   else
15629     {
15630       priv->paint_volume_valid = FALSE;
15631       return NULL;
15632     }
15633 }
15634
15635 /**
15636  * clutter_actor_get_paint_volume:
15637  * @self: a #ClutterActor
15638  *
15639  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15640  * when a paint volume can't be determined.
15641  *
15642  * The paint volume is defined as the 3D space occupied by an actor
15643  * when being painted.
15644  *
15645  * This function will call the <function>get_paint_volume()</function>
15646  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15647  * should not usually care about overriding the default implementation,
15648  * unless they are, for instance: painting outside their allocation, or
15649  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15650  * 3D depth).
15651  *
15652  * <note>2D actors overriding <function>get_paint_volume()</function>
15653  * ensure their volume has a depth of 0. (This will be true so long as
15654  * you don't call clutter_paint_volume_set_depth().)</note>
15655  *
15656  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15657  *   or %NULL if no volume could be determined. The returned pointer
15658  *   is not guaranteed to be valid across multiple frames; if you want
15659  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15660  *
15661  * Since: 1.6
15662  */
15663 const ClutterPaintVolume *
15664 clutter_actor_get_paint_volume (ClutterActor *self)
15665 {
15666   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15667
15668   return _clutter_actor_get_paint_volume_mutable (self);
15669 }
15670
15671 /**
15672  * clutter_actor_get_transformed_paint_volume:
15673  * @self: a #ClutterActor
15674  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15675  *    (or %NULL for the stage)
15676  *
15677  * Retrieves the 3D paint volume of an actor like
15678  * clutter_actor_get_paint_volume() does (Please refer to the
15679  * documentation of clutter_actor_get_paint_volume() for more
15680  * details.) and it additionally transforms the paint volume into the
15681  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15682  * is passed for @relative_to_ancestor)
15683  *
15684  * This can be used by containers that base their paint volume on
15685  * the volume of their children. Such containers can query the
15686  * transformed paint volume of all of its children and union them
15687  * together using clutter_paint_volume_union().
15688  *
15689  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15690  *   or %NULL if no volume could be determined. The returned pointer is
15691  *   not guaranteed to be valid across multiple frames; if you wish to
15692  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15693  *
15694  * Since: 1.6
15695  */
15696 const ClutterPaintVolume *
15697 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15698                                             ClutterActor *relative_to_ancestor)
15699 {
15700   const ClutterPaintVolume *volume;
15701   ClutterActor *stage;
15702   ClutterPaintVolume *transformed_volume;
15703
15704   stage = _clutter_actor_get_stage_internal (self);
15705   if (G_UNLIKELY (stage == NULL))
15706     return NULL;
15707
15708   if (relative_to_ancestor == NULL)
15709     relative_to_ancestor = stage;
15710
15711   volume = clutter_actor_get_paint_volume (self);
15712   if (volume == NULL)
15713     return NULL;
15714
15715   transformed_volume =
15716     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15717
15718   _clutter_paint_volume_copy_static (volume, transformed_volume);
15719
15720   _clutter_paint_volume_transform_relative (transformed_volume,
15721                                             relative_to_ancestor);
15722
15723   return transformed_volume;
15724 }
15725
15726 /**
15727  * clutter_actor_get_paint_box:
15728  * @self: a #ClutterActor
15729  * @box: (out): return location for a #ClutterActorBox
15730  *
15731  * Retrieves the paint volume of the passed #ClutterActor, and
15732  * transforms it into a 2D bounding box in stage coordinates.
15733  *
15734  * This function is useful to determine the on screen area occupied by
15735  * the actor. The box is only an approximation and may often be
15736  * considerably larger due to the optimizations used to calculate the
15737  * box. The box is never smaller though, so it can reliably be used
15738  * for culling.
15739  *
15740  * There are times when a 2D paint box can't be determined, e.g.
15741  * because the actor isn't yet parented under a stage or because
15742  * the actor is unable to determine a paint volume.
15743  *
15744  * Return value: %TRUE if a 2D paint box could be determined, else
15745  * %FALSE.
15746  *
15747  * Since: 1.6
15748  */
15749 gboolean
15750 clutter_actor_get_paint_box (ClutterActor    *self,
15751                              ClutterActorBox *box)
15752 {
15753   ClutterActor *stage;
15754   ClutterPaintVolume *pv;
15755
15756   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15757   g_return_val_if_fail (box != NULL, FALSE);
15758
15759   stage = _clutter_actor_get_stage_internal (self);
15760   if (G_UNLIKELY (!stage))
15761     return FALSE;
15762
15763   pv = _clutter_actor_get_paint_volume_mutable (self);
15764   if (G_UNLIKELY (!pv))
15765     return FALSE;
15766
15767   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15768
15769   return TRUE;
15770 }
15771
15772 /**
15773  * clutter_actor_has_overlaps:
15774  * @self: A #ClutterActor
15775  *
15776  * Asks the actor's implementation whether it may contain overlapping
15777  * primitives.
15778  *
15779  * For example; Clutter may use this to determine whether the painting
15780  * should be redirected to an offscreen buffer to correctly implement
15781  * the opacity property.
15782  *
15783  * Custom actors can override the default response by implementing the
15784  * #ClutterActor <function>has_overlaps</function> virtual function. See
15785  * clutter_actor_set_offscreen_redirect() for more information.
15786  *
15787  * Return value: %TRUE if the actor may have overlapping primitives, and
15788  *   %FALSE otherwise
15789  *
15790  * Since: 1.8
15791  */
15792 gboolean
15793 clutter_actor_has_overlaps (ClutterActor *self)
15794 {
15795   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15796
15797   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15798 }
15799
15800 /**
15801  * clutter_actor_has_effects:
15802  * @self: A #ClutterActor
15803  *
15804  * Returns whether the actor has any effects applied.
15805  *
15806  * Return value: %TRUE if the actor has any effects,
15807  *   %FALSE otherwise
15808  *
15809  * Since: 1.10
15810  */
15811 gboolean
15812 clutter_actor_has_effects (ClutterActor *self)
15813 {
15814   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15815
15816   if (self->priv->effects == NULL)
15817     return FALSE;
15818
15819   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15820 }
15821
15822 /**
15823  * clutter_actor_has_constraints:
15824  * @self: A #ClutterActor
15825  *
15826  * Returns whether the actor has any constraints applied.
15827  *
15828  * Return value: %TRUE if the actor has any constraints,
15829  *   %FALSE otherwise
15830  *
15831  * Since: 1.10
15832  */
15833 gboolean
15834 clutter_actor_has_constraints (ClutterActor *self)
15835 {
15836   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15837
15838   return self->priv->constraints != NULL;
15839 }
15840
15841 /**
15842  * clutter_actor_has_actions:
15843  * @self: A #ClutterActor
15844  *
15845  * Returns whether the actor has any actions applied.
15846  *
15847  * Return value: %TRUE if the actor has any actions,
15848  *   %FALSE otherwise
15849  *
15850  * Since: 1.10
15851  */
15852 gboolean
15853 clutter_actor_has_actions (ClutterActor *self)
15854 {
15855   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15856
15857   return self->priv->actions != NULL;
15858 }
15859
15860 /**
15861  * clutter_actor_get_n_children:
15862  * @self: a #ClutterActor
15863  *
15864  * Retrieves the number of children of @self.
15865  *
15866  * Return value: the number of children of an actor
15867  *
15868  * Since: 1.10
15869  */
15870 gint
15871 clutter_actor_get_n_children (ClutterActor *self)
15872 {
15873   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15874
15875   return self->priv->n_children;
15876 }
15877
15878 /**
15879  * clutter_actor_get_child_at_index:
15880  * @self: a #ClutterActor
15881  * @index_: the position in the list of children
15882  *
15883  * Retrieves the actor at the given @index_ inside the list of
15884  * children of @self.
15885  *
15886  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15887  *
15888  * Since: 1.10
15889  */
15890 ClutterActor *
15891 clutter_actor_get_child_at_index (ClutterActor *self,
15892                                   gint          index_)
15893 {
15894   ClutterActor *iter;
15895   int i;
15896
15897   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15898   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15899
15900   for (iter = self->priv->first_child, i = 0;
15901        iter != NULL && i < index_;
15902        iter = iter->priv->next_sibling, i += 1)
15903     ;
15904
15905   return iter;
15906 }
15907
15908 /*< private >
15909  * _clutter_actor_foreach_child:
15910  * @actor: The actor whos children you want to iterate
15911  * @callback: The function to call for each child
15912  * @user_data: Private data to pass to @callback
15913  *
15914  * Calls a given @callback once for each child of the specified @actor and
15915  * passing the @user_data pointer each time.
15916  *
15917  * Return value: returns %TRUE if all children were iterated, else
15918  *    %FALSE if a callback broke out of iteration early.
15919  */
15920 gboolean
15921 _clutter_actor_foreach_child (ClutterActor           *self,
15922                               ClutterForeachCallback  callback,
15923                               gpointer                user_data)
15924 {
15925   ClutterActor *iter;
15926   gboolean cont;
15927
15928   if (self->priv->first_child == NULL)
15929     return TRUE;
15930
15931   cont = TRUE;
15932   iter = self->priv->first_child;
15933
15934   /* we use this form so that it's safe to change the children
15935    * list while iterating it
15936    */
15937   while (cont && iter != NULL)
15938     {
15939       ClutterActor *next = iter->priv->next_sibling;
15940
15941       cont = callback (iter, user_data);
15942
15943       iter = next;
15944     }
15945
15946   return cont;
15947 }
15948
15949 #if 0
15950 /* For debugging purposes this gives us a simple way to print out
15951  * the scenegraph e.g in gdb using:
15952  * [|
15953  *   _clutter_actor_traverse (stage,
15954  *                            0,
15955  *                            clutter_debug_print_actor_cb,
15956  *                            NULL,
15957  *                            NULL);
15958  * |]
15959  */
15960 static ClutterActorTraverseVisitFlags
15961 clutter_debug_print_actor_cb (ClutterActor *actor,
15962                               int depth,
15963                               void *user_data)
15964 {
15965   g_print ("%*s%s:%p\n",
15966            depth * 2, "",
15967            _clutter_actor_get_debug_name (actor),
15968            actor);
15969
15970   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15971 }
15972 #endif
15973
15974 static void
15975 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15976                                  ClutterTraverseCallback callback,
15977                                  gpointer                user_data)
15978 {
15979   GQueue *queue = g_queue_new ();
15980   ClutterActor dummy;
15981   int current_depth = 0;
15982
15983   g_queue_push_tail (queue, actor);
15984   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15985
15986   while ((actor = g_queue_pop_head (queue)))
15987     {
15988       ClutterActorTraverseVisitFlags flags;
15989
15990       if (actor == &dummy)
15991         {
15992           current_depth++;
15993           g_queue_push_tail (queue, &dummy);
15994           continue;
15995         }
15996
15997       flags = callback (actor, current_depth, user_data);
15998       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15999         break;
16000       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16001         {
16002           ClutterActor *iter;
16003
16004           for (iter = actor->priv->first_child;
16005                iter != NULL;
16006                iter = iter->priv->next_sibling)
16007             {
16008               g_queue_push_tail (queue, iter);
16009             }
16010         }
16011     }
16012
16013   g_queue_free (queue);
16014 }
16015
16016 static ClutterActorTraverseVisitFlags
16017 _clutter_actor_traverse_depth (ClutterActor           *actor,
16018                                ClutterTraverseCallback before_children_callback,
16019                                ClutterTraverseCallback after_children_callback,
16020                                int                     current_depth,
16021                                gpointer                user_data)
16022 {
16023   ClutterActorTraverseVisitFlags flags;
16024
16025   flags = before_children_callback (actor, current_depth, user_data);
16026   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16027     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16028
16029   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16030     {
16031       ClutterActor *iter;
16032
16033       for (iter = actor->priv->first_child;
16034            iter != NULL;
16035            iter = iter->priv->next_sibling)
16036         {
16037           flags = _clutter_actor_traverse_depth (iter,
16038                                                  before_children_callback,
16039                                                  after_children_callback,
16040                                                  current_depth + 1,
16041                                                  user_data);
16042
16043           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16044             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16045         }
16046     }
16047
16048   if (after_children_callback)
16049     return after_children_callback (actor, current_depth, user_data);
16050   else
16051     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16052 }
16053
16054 /* _clutter_actor_traverse:
16055  * @actor: The actor to start traversing the graph from
16056  * @flags: These flags may affect how the traversal is done
16057  * @before_children_callback: A function to call before visiting the
16058  *   children of the current actor.
16059  * @after_children_callback: A function to call after visiting the
16060  *   children of the current actor. (Ignored if
16061  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
16062  * @user_data: The private data to pass to the callbacks
16063  *
16064  * Traverses the scenegraph starting at the specified @actor and
16065  * descending through all its children and its children's children.
16066  * For each actor traversed @before_children_callback and
16067  * @after_children_callback are called with the specified
16068  * @user_data, before and after visiting that actor's children.
16069  *
16070  * The callbacks can return flags that affect the ongoing traversal
16071  * such as by skipping over an actors children or bailing out of
16072  * any further traversing.
16073  */
16074 void
16075 _clutter_actor_traverse (ClutterActor              *actor,
16076                          ClutterActorTraverseFlags  flags,
16077                          ClutterTraverseCallback    before_children_callback,
16078                          ClutterTraverseCallback    after_children_callback,
16079                          gpointer                   user_data)
16080 {
16081   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
16082     _clutter_actor_traverse_breadth (actor,
16083                                      before_children_callback,
16084                                      user_data);
16085   else /* DEPTH_FIRST */
16086     _clutter_actor_traverse_depth (actor,
16087                                    before_children_callback,
16088                                    after_children_callback,
16089                                    0, /* start depth */
16090                                    user_data);
16091 }
16092
16093 static void
16094 on_layout_manager_changed (ClutterLayoutManager *manager,
16095                            ClutterActor         *self)
16096 {
16097   clutter_actor_queue_relayout (self);
16098 }
16099
16100 /**
16101  * clutter_actor_set_layout_manager:
16102  * @self: a #ClutterActor
16103  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
16104  *
16105  * Sets the #ClutterLayoutManager delegate object that will be used to
16106  * lay out the children of @self.
16107  *
16108  * The #ClutterActor will take a reference on the passed @manager which
16109  * will be released either when the layout manager is removed, or when
16110  * the actor is destroyed.
16111  *
16112  * Since: 1.10
16113  */
16114 void
16115 clutter_actor_set_layout_manager (ClutterActor         *self,
16116                                   ClutterLayoutManager *manager)
16117 {
16118   ClutterActorPrivate *priv;
16119
16120   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16121   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16122
16123   priv = self->priv;
16124
16125   if (priv->layout_manager != NULL)
16126     {
16127       g_signal_handlers_disconnect_by_func (priv->layout_manager,
16128                                             G_CALLBACK (on_layout_manager_changed),
16129                                             self);
16130       clutter_layout_manager_set_container (priv->layout_manager, NULL);
16131       g_clear_object (&priv->layout_manager);
16132     }
16133
16134   priv->layout_manager = manager;
16135
16136   if (priv->layout_manager != NULL)
16137     {
16138       g_object_ref_sink (priv->layout_manager);
16139       clutter_layout_manager_set_container (priv->layout_manager,
16140                                             CLUTTER_CONTAINER (self));
16141       g_signal_connect (priv->layout_manager, "layout-changed",
16142                         G_CALLBACK (on_layout_manager_changed),
16143                         self);
16144     }
16145
16146   clutter_actor_queue_relayout (self);
16147
16148   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16149 }
16150
16151 /**
16152  * clutter_actor_get_layout_manager:
16153  * @self: a #ClutterActor
16154  *
16155  * Retrieves the #ClutterLayoutManager used by @self.
16156  *
16157  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16158  *   or %NULL
16159  *
16160  * Since: 1.10
16161  */
16162 ClutterLayoutManager *
16163 clutter_actor_get_layout_manager (ClutterActor *self)
16164 {
16165   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16166
16167   return self->priv->layout_manager;
16168 }
16169
16170 static const ClutterLayoutInfo default_layout_info = {
16171   CLUTTER_POINT_INIT_ZERO,      /* fixed-pos */
16172   { 0, 0, 0, 0 },               /* margin */
16173   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
16174   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
16175   FALSE, FALSE,                 /* expand */
16176   CLUTTER_SIZE_INIT_ZERO,       /* minimum */
16177   CLUTTER_SIZE_INIT_ZERO,       /* natural */
16178 };
16179
16180 static void
16181 layout_info_free (gpointer data)
16182 {
16183   if (G_LIKELY (data != NULL))
16184     g_slice_free (ClutterLayoutInfo, data);
16185 }
16186
16187 /*< private >
16188  * _clutter_actor_get_layout_info:
16189  * @self: a #ClutterActor
16190  *
16191  * Retrieves a pointer to the ClutterLayoutInfo structure.
16192  *
16193  * If the actor does not have a ClutterLayoutInfo associated to it, one
16194  * will be created and initialized to the default values.
16195  *
16196  * This function should be used for setters.
16197  *
16198  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16199  * instead.
16200  *
16201  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16202  */
16203 ClutterLayoutInfo *
16204 _clutter_actor_get_layout_info (ClutterActor *self)
16205 {
16206   ClutterLayoutInfo *retval;
16207
16208   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16209   if (retval == NULL)
16210     {
16211       retval = g_slice_new (ClutterLayoutInfo);
16212
16213       *retval = default_layout_info;
16214
16215       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16216                                retval,
16217                                layout_info_free);
16218     }
16219
16220   return retval;
16221 }
16222
16223 /*< private >
16224  * _clutter_actor_get_layout_info_or_defaults:
16225  * @self: a #ClutterActor
16226  *
16227  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16228  *
16229  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16230  * then the default structure will be returned.
16231  *
16232  * This function should only be used for getters.
16233  *
16234  * Return value: a const pointer to the ClutterLayoutInfo structure
16235  */
16236 const ClutterLayoutInfo *
16237 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16238 {
16239   const ClutterLayoutInfo *info;
16240
16241   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16242   if (info == NULL)
16243     return &default_layout_info;
16244
16245   return info;
16246 }
16247
16248 /**
16249  * clutter_actor_set_x_align:
16250  * @self: a #ClutterActor
16251  * @x_align: the horizontal alignment policy
16252  *
16253  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16254  * actor received extra horizontal space.
16255  *
16256  * See also the #ClutterActor:x-align property.
16257  *
16258  * Since: 1.10
16259  */
16260 void
16261 clutter_actor_set_x_align (ClutterActor      *self,
16262                            ClutterActorAlign  x_align)
16263 {
16264   ClutterLayoutInfo *info;
16265
16266   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16267
16268   info = _clutter_actor_get_layout_info (self);
16269
16270   if (info->x_align != x_align)
16271     {
16272       info->x_align = x_align;
16273
16274       clutter_actor_queue_relayout (self);
16275
16276       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16277     }
16278 }
16279
16280 /**
16281  * clutter_actor_get_x_align:
16282  * @self: a #ClutterActor
16283  *
16284  * Retrieves the horizontal alignment policy set using
16285  * clutter_actor_set_x_align().
16286  *
16287  * Return value: the horizontal alignment policy.
16288  *
16289  * Since: 1.10
16290  */
16291 ClutterActorAlign
16292 clutter_actor_get_x_align (ClutterActor *self)
16293 {
16294   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16295
16296   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16297 }
16298
16299 /**
16300  * clutter_actor_set_y_align:
16301  * @self: a #ClutterActor
16302  * @y_align: the vertical alignment policy
16303  *
16304  * Sets the vertical alignment policy of a #ClutterActor, in case the
16305  * actor received extra vertical space.
16306  *
16307  * See also the #ClutterActor:y-align property.
16308  *
16309  * Since: 1.10
16310  */
16311 void
16312 clutter_actor_set_y_align (ClutterActor      *self,
16313                            ClutterActorAlign  y_align)
16314 {
16315   ClutterLayoutInfo *info;
16316
16317   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16318
16319   info = _clutter_actor_get_layout_info (self);
16320
16321   if (info->y_align != y_align)
16322     {
16323       info->y_align = y_align;
16324
16325       clutter_actor_queue_relayout (self);
16326
16327       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16328     }
16329 }
16330
16331 /**
16332  * clutter_actor_get_y_align:
16333  * @self: a #ClutterActor
16334  *
16335  * Retrieves the vertical alignment policy set using
16336  * clutter_actor_set_y_align().
16337  *
16338  * Return value: the vertical alignment policy.
16339  *
16340  * Since: 1.10
16341  */
16342 ClutterActorAlign
16343 clutter_actor_get_y_align (ClutterActor *self)
16344 {
16345   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16346
16347   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16348 }
16349
16350 /**
16351  * clutter_actor_set_margin:
16352  * @self: a #ClutterActor
16353  * @margin: a #ClutterMargin
16354  *
16355  * Sets all the components of the margin of a #ClutterActor.
16356  *
16357  * Since: 1.10
16358  */
16359 void
16360 clutter_actor_set_margin (ClutterActor        *self,
16361                           const ClutterMargin *margin)
16362 {
16363   ClutterLayoutInfo *info;
16364   gboolean changed;
16365   GObject *obj;
16366
16367   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16368   g_return_if_fail (margin != NULL);
16369
16370   obj = G_OBJECT (self);
16371   changed = FALSE;
16372
16373   g_object_freeze_notify (obj);
16374
16375   info = _clutter_actor_get_layout_info (self);
16376
16377   if (info->margin.top != margin->top)
16378     {
16379       info->margin.top = margin->top;
16380       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16381       changed = TRUE;
16382     }
16383
16384   if (info->margin.right != margin->right)
16385     {
16386       info->margin.right = margin->right;
16387       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16388       changed = TRUE;
16389     }
16390
16391   if (info->margin.bottom != margin->bottom)
16392     {
16393       info->margin.bottom = margin->bottom;
16394       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16395       changed = TRUE;
16396     }
16397
16398   if (info->margin.left != margin->left)
16399     {
16400       info->margin.left = margin->left;
16401       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16402       changed = TRUE;
16403     }
16404
16405   if (changed)
16406     clutter_actor_queue_relayout (self);
16407
16408   g_object_thaw_notify (obj);
16409 }
16410
16411 /**
16412  * clutter_actor_get_margin:
16413  * @self: a #ClutterActor
16414  * @margin: (out caller-allocates): return location for a #ClutterMargin
16415  *
16416  * Retrieves all the components of the margin of a #ClutterActor.
16417  *
16418  * Since: 1.10
16419  */
16420 void
16421 clutter_actor_get_margin (ClutterActor  *self,
16422                           ClutterMargin *margin)
16423 {
16424   const ClutterLayoutInfo *info;
16425
16426   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16427   g_return_if_fail (margin != NULL);
16428
16429   info = _clutter_actor_get_layout_info_or_defaults (self);
16430
16431   *margin = info->margin;
16432 }
16433
16434 /**
16435  * clutter_actor_set_margin_top:
16436  * @self: a #ClutterActor
16437  * @margin: the top margin
16438  *
16439  * Sets the margin from the top of a #ClutterActor.
16440  *
16441  * Since: 1.10
16442  */
16443 void
16444 clutter_actor_set_margin_top (ClutterActor *self,
16445                               gfloat        margin)
16446 {
16447   ClutterLayoutInfo *info;
16448
16449   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16450   g_return_if_fail (margin >= 0.f);
16451
16452   info = _clutter_actor_get_layout_info (self);
16453
16454   if (info->margin.top == margin)
16455     return;
16456
16457   info->margin.top = margin;
16458
16459   clutter_actor_queue_relayout (self);
16460
16461   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16462 }
16463
16464 /**
16465  * clutter_actor_get_margin_top:
16466  * @self: a #ClutterActor
16467  *
16468  * Retrieves the top margin of a #ClutterActor.
16469  *
16470  * Return value: the top margin
16471  *
16472  * Since: 1.10
16473  */
16474 gfloat
16475 clutter_actor_get_margin_top (ClutterActor *self)
16476 {
16477   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16478
16479   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16480 }
16481
16482 /**
16483  * clutter_actor_set_margin_bottom:
16484  * @self: a #ClutterActor
16485  * @margin: the bottom margin
16486  *
16487  * Sets the margin from the bottom of a #ClutterActor.
16488  *
16489  * Since: 1.10
16490  */
16491 void
16492 clutter_actor_set_margin_bottom (ClutterActor *self,
16493                                  gfloat        margin)
16494 {
16495   ClutterLayoutInfo *info;
16496
16497   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16498   g_return_if_fail (margin >= 0.f);
16499
16500   info = _clutter_actor_get_layout_info (self);
16501
16502   if (info->margin.bottom == margin)
16503     return;
16504
16505   info->margin.bottom = margin;
16506
16507   clutter_actor_queue_relayout (self);
16508
16509   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16510 }
16511
16512 /**
16513  * clutter_actor_get_margin_bottom:
16514  * @self: a #ClutterActor
16515  *
16516  * Retrieves the bottom margin of a #ClutterActor.
16517  *
16518  * Return value: the bottom margin
16519  *
16520  * Since: 1.10
16521  */
16522 gfloat
16523 clutter_actor_get_margin_bottom (ClutterActor *self)
16524 {
16525   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16526
16527   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16528 }
16529
16530 /**
16531  * clutter_actor_set_margin_left:
16532  * @self: a #ClutterActor
16533  * @margin: the left margin
16534  *
16535  * Sets the margin from the left of a #ClutterActor.
16536  *
16537  * Since: 1.10
16538  */
16539 void
16540 clutter_actor_set_margin_left (ClutterActor *self,
16541                                gfloat        margin)
16542 {
16543   ClutterLayoutInfo *info;
16544
16545   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16546   g_return_if_fail (margin >= 0.f);
16547
16548   info = _clutter_actor_get_layout_info (self);
16549
16550   if (info->margin.left == margin)
16551     return;
16552
16553   info->margin.left = margin;
16554
16555   clutter_actor_queue_relayout (self);
16556
16557   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16558 }
16559
16560 /**
16561  * clutter_actor_get_margin_left:
16562  * @self: a #ClutterActor
16563  *
16564  * Retrieves the left margin of a #ClutterActor.
16565  *
16566  * Return value: the left margin
16567  *
16568  * Since: 1.10
16569  */
16570 gfloat
16571 clutter_actor_get_margin_left (ClutterActor *self)
16572 {
16573   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16574
16575   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16576 }
16577
16578 /**
16579  * clutter_actor_set_margin_right:
16580  * @self: a #ClutterActor
16581  * @margin: the right margin
16582  *
16583  * Sets the margin from the right of a #ClutterActor.
16584  *
16585  * Since: 1.10
16586  */
16587 void
16588 clutter_actor_set_margin_right (ClutterActor *self,
16589                                 gfloat        margin)
16590 {
16591   ClutterLayoutInfo *info;
16592
16593   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16594   g_return_if_fail (margin >= 0.f);
16595
16596   info = _clutter_actor_get_layout_info (self);
16597
16598   if (info->margin.right == margin)
16599     return;
16600
16601   info->margin.right = margin;
16602
16603   clutter_actor_queue_relayout (self);
16604
16605   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16606 }
16607
16608 /**
16609  * clutter_actor_get_margin_right:
16610  * @self: a #ClutterActor
16611  *
16612  * Retrieves the right margin of a #ClutterActor.
16613  *
16614  * Return value: the right margin
16615  *
16616  * Since: 1.10
16617  */
16618 gfloat
16619 clutter_actor_get_margin_right (ClutterActor *self)
16620 {
16621   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16622
16623   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16624 }
16625
16626 static inline void
16627 clutter_actor_set_background_color_internal (ClutterActor *self,
16628                                              const ClutterColor *color)
16629 {
16630   ClutterActorPrivate *priv = self->priv;
16631   GObject *obj;
16632
16633   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16634     return;
16635
16636   obj = G_OBJECT (self);
16637
16638   priv->bg_color = *color;
16639   priv->bg_color_set = TRUE;
16640
16641   clutter_actor_queue_redraw (self);
16642
16643   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16644   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16645 }
16646
16647 /**
16648  * clutter_actor_set_background_color:
16649  * @self: a #ClutterActor
16650  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16651  *  set color
16652  *
16653  * Sets the background color of a #ClutterActor.
16654  *
16655  * The background color will be used to cover the whole allocation of the
16656  * actor. The default background color of an actor is transparent.
16657  *
16658  * To check whether an actor has a background color, you can use the
16659  * #ClutterActor:background-color-set actor property.
16660  *
16661  * The #ClutterActor:background-color property is animatable.
16662  *
16663  * Since: 1.10
16664  */
16665 void
16666 clutter_actor_set_background_color (ClutterActor       *self,
16667                                     const ClutterColor *color)
16668 {
16669   ClutterActorPrivate *priv;
16670   GObject *obj;
16671   GParamSpec *bg_color_pspec;
16672
16673   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16674
16675   obj = G_OBJECT (self);
16676
16677   priv = self->priv;
16678
16679   if (color == NULL)
16680     {
16681       priv->bg_color_set = FALSE;
16682       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16683       clutter_actor_queue_redraw (self);
16684       return;
16685     }
16686
16687   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16688   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16689     {
16690       _clutter_actor_create_transition (self, bg_color_pspec,
16691                                         &priv->bg_color,
16692                                         color);
16693     }
16694   else
16695     _clutter_actor_update_transition (self, bg_color_pspec, color);
16696
16697   clutter_actor_queue_redraw (self);
16698 }
16699
16700 /**
16701  * clutter_actor_get_background_color:
16702  * @self: a #ClutterActor
16703  * @color: (out caller-allocates): return location for a #ClutterColor
16704  *
16705  * Retrieves the color set using clutter_actor_set_background_color().
16706  *
16707  * Since: 1.10
16708  */
16709 void
16710 clutter_actor_get_background_color (ClutterActor *self,
16711                                     ClutterColor *color)
16712 {
16713   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16714   g_return_if_fail (color != NULL);
16715
16716   *color = self->priv->bg_color;
16717 }
16718
16719 /**
16720  * clutter_actor_get_previous_sibling:
16721  * @self: a #ClutterActor
16722  *
16723  * Retrieves the sibling of @self that comes before it in the list
16724  * of children of @self's parent.
16725  *
16726  * The returned pointer is only valid until the scene graph changes; it
16727  * is not safe to modify the list of children of @self while iterating
16728  * it.
16729  *
16730  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16731  *
16732  * Since: 1.10
16733  */
16734 ClutterActor *
16735 clutter_actor_get_previous_sibling (ClutterActor *self)
16736 {
16737   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16738
16739   return self->priv->prev_sibling;
16740 }
16741
16742 /**
16743  * clutter_actor_get_next_sibling:
16744  * @self: a #ClutterActor
16745  *
16746  * Retrieves the sibling of @self that comes after it in the list
16747  * of children of @self's parent.
16748  *
16749  * The returned pointer is only valid until the scene graph changes; it
16750  * is not safe to modify the list of children of @self while iterating
16751  * it.
16752  *
16753  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16754  *
16755  * Since: 1.10
16756  */
16757 ClutterActor *
16758 clutter_actor_get_next_sibling (ClutterActor *self)
16759 {
16760   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16761
16762   return self->priv->next_sibling;
16763 }
16764
16765 /**
16766  * clutter_actor_get_first_child:
16767  * @self: a #ClutterActor
16768  *
16769  * Retrieves the first child of @self.
16770  *
16771  * The returned pointer is only valid until the scene graph changes; it
16772  * is not safe to modify the list of children of @self while iterating
16773  * it.
16774  *
16775  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16776  *
16777  * Since: 1.10
16778  */
16779 ClutterActor *
16780 clutter_actor_get_first_child (ClutterActor *self)
16781 {
16782   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16783
16784   return self->priv->first_child;
16785 }
16786
16787 /**
16788  * clutter_actor_get_last_child:
16789  * @self: a #ClutterActor
16790  *
16791  * Retrieves the last child of @self.
16792  *
16793  * The returned pointer is only valid until the scene graph changes; it
16794  * is not safe to modify the list of children of @self while iterating
16795  * it.
16796  *
16797  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16798  *
16799  * Since: 1.10
16800  */
16801 ClutterActor *
16802 clutter_actor_get_last_child (ClutterActor *self)
16803 {
16804   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16805
16806   return self->priv->last_child;
16807 }
16808
16809 /* easy way to have properly named fields instead of the dummy ones
16810  * we use in the public structure
16811  */
16812 typedef struct _RealActorIter
16813 {
16814   ClutterActor *root;           /* dummy1 */
16815   ClutterActor *current;        /* dummy2 */
16816   gpointer padding_1;           /* dummy3 */
16817   gint age;                     /* dummy4 */
16818   gpointer padding_2;           /* dummy5 */
16819 } RealActorIter;
16820
16821 /**
16822  * clutter_actor_iter_init:
16823  * @iter: a #ClutterActorIter
16824  * @root: a #ClutterActor
16825  *
16826  * Initializes a #ClutterActorIter, which can then be used to iterate
16827  * efficiently over a section of the scene graph, and associates it
16828  * with @root.
16829  *
16830  * Modifying the scene graph section that contains @root will invalidate
16831  * the iterator.
16832  *
16833  * |[
16834  *   ClutterActorIter iter;
16835  *   ClutterActor *child;
16836  *
16837  *   clutter_actor_iter_init (&iter, container);
16838  *   while (clutter_actor_iter_next (&iter, &child))
16839  *     {
16840  *       /&ast; do something with child &ast;/
16841  *     }
16842  * ]|
16843  *
16844  * Since: 1.10
16845  */
16846 void
16847 clutter_actor_iter_init (ClutterActorIter *iter,
16848                          ClutterActor     *root)
16849 {
16850   RealActorIter *ri = (RealActorIter *) iter;
16851
16852   g_return_if_fail (iter != NULL);
16853   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16854
16855   ri->root = root;
16856   ri->current = NULL;
16857   ri->age = root->priv->age;
16858 }
16859
16860 /**
16861  * clutter_actor_iter_next:
16862  * @iter: a #ClutterActorIter
16863  * @child: (out): return location for a #ClutterActor
16864  *
16865  * Advances the @iter and retrieves the next child of the root #ClutterActor
16866  * that was used to initialize the #ClutterActorIterator.
16867  *
16868  * If the iterator can advance, this function returns %TRUE and sets the
16869  * @child argument.
16870  *
16871  * If the iterator cannot advance, this function returns %FALSE, and
16872  * the contents of @child are undefined.
16873  *
16874  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16875  *
16876  * Since: 1.10
16877  */
16878 gboolean
16879 clutter_actor_iter_next (ClutterActorIter  *iter,
16880                          ClutterActor     **child)
16881 {
16882   RealActorIter *ri = (RealActorIter *) iter;
16883
16884   g_return_val_if_fail (iter != NULL, FALSE);
16885   g_return_val_if_fail (ri->root != NULL, FALSE);
16886 #ifndef G_DISABLE_ASSERT
16887   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16888 #endif
16889
16890   if (ri->current == NULL)
16891     ri->current = ri->root->priv->first_child;
16892   else
16893     ri->current = ri->current->priv->next_sibling;
16894
16895   if (child != NULL)
16896     *child = ri->current;
16897
16898   return ri->current != NULL;
16899 }
16900
16901 /**
16902  * clutter_actor_iter_prev:
16903  * @iter: a #ClutterActorIter
16904  * @child: (out): return location for a #ClutterActor
16905  *
16906  * Advances the @iter and retrieves the previous child of the root
16907  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16908  *
16909  * If the iterator can advance, this function returns %TRUE and sets the
16910  * @child argument.
16911  *
16912  * If the iterator cannot advance, this function returns %FALSE, and
16913  * the contents of @child are undefined.
16914  *
16915  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16916  *
16917  * Since: 1.10
16918  */
16919 gboolean
16920 clutter_actor_iter_prev (ClutterActorIter  *iter,
16921                          ClutterActor     **child)
16922 {
16923   RealActorIter *ri = (RealActorIter *) iter;
16924
16925   g_return_val_if_fail (iter != NULL, FALSE);
16926   g_return_val_if_fail (ri->root != NULL, FALSE);
16927 #ifndef G_DISABLE_ASSERT
16928   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16929 #endif
16930
16931   if (ri->current == NULL)
16932     ri->current = ri->root->priv->last_child;
16933   else
16934     ri->current = ri->current->priv->prev_sibling;
16935
16936   if (child != NULL)
16937     *child = ri->current;
16938
16939   return ri->current != NULL;
16940 }
16941
16942 /**
16943  * clutter_actor_iter_remove:
16944  * @iter: a #ClutterActorIter
16945  *
16946  * Safely removes the #ClutterActor currently pointer to by the iterator
16947  * from its parent.
16948  *
16949  * This function can only be called after clutter_actor_iter_next() or
16950  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16951  * than once for the same actor.
16952  *
16953  * This function will call clutter_actor_remove_child() internally.
16954  *
16955  * Since: 1.10
16956  */
16957 void
16958 clutter_actor_iter_remove (ClutterActorIter *iter)
16959 {
16960   RealActorIter *ri = (RealActorIter *) iter;
16961   ClutterActor *cur;
16962
16963   g_return_if_fail (iter != NULL);
16964   g_return_if_fail (ri->root != NULL);
16965 #ifndef G_DISABLE_ASSERT
16966   g_return_if_fail (ri->age == ri->root->priv->age);
16967 #endif
16968   g_return_if_fail (ri->current != NULL);
16969
16970   cur = ri->current;
16971
16972   if (cur != NULL)
16973     {
16974       ri->current = cur->priv->prev_sibling;
16975
16976       clutter_actor_remove_child_internal (ri->root, cur,
16977                                            REMOVE_CHILD_DEFAULT_FLAGS);
16978
16979       ri->age += 1;
16980     }
16981 }
16982
16983 /**
16984  * clutter_actor_iter_destroy:
16985  * @iter: a #ClutterActorIter
16986  *
16987  * Safely destroys the #ClutterActor currently pointer to by the iterator
16988  * from its parent.
16989  *
16990  * This function can only be called after clutter_actor_iter_next() or
16991  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16992  * than once for the same actor.
16993  *
16994  * This function will call clutter_actor_destroy() internally.
16995  *
16996  * Since: 1.10
16997  */
16998 void
16999 clutter_actor_iter_destroy (ClutterActorIter *iter)
17000 {
17001   RealActorIter *ri = (RealActorIter *) iter;
17002   ClutterActor *cur;
17003
17004   g_return_if_fail (iter != NULL);
17005   g_return_if_fail (ri->root != NULL);
17006 #ifndef G_DISABLE_ASSERT
17007   g_return_if_fail (ri->age == ri->root->priv->age);
17008 #endif
17009   g_return_if_fail (ri->current != NULL);
17010
17011   cur = ri->current;
17012
17013   if (cur != NULL)
17014     {
17015       ri->current = cur->priv->prev_sibling;
17016
17017       clutter_actor_destroy (cur);
17018
17019       ri->age += 1;
17020     }
17021 }
17022
17023 static const ClutterAnimationInfo default_animation_info = {
17024   NULL,         /* transitions */
17025   NULL,         /* states */
17026   NULL,         /* cur_state */
17027 };
17028
17029 static void
17030 clutter_animation_info_free (gpointer data)
17031 {
17032   if (data != NULL)
17033     {
17034       ClutterAnimationInfo *info = data;
17035
17036       if (info->transitions != NULL)
17037         g_hash_table_unref (info->transitions);
17038
17039       if (info->states != NULL)
17040         g_array_unref (info->states);
17041
17042       g_slice_free (ClutterAnimationInfo, info);
17043     }
17044 }
17045
17046 const ClutterAnimationInfo *
17047 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17048 {
17049   const ClutterAnimationInfo *res;
17050   GObject *obj = G_OBJECT (self);
17051
17052   res = g_object_get_qdata (obj, quark_actor_animation_info);
17053   if (res != NULL)
17054     return res;
17055
17056   return &default_animation_info;
17057 }
17058
17059 ClutterAnimationInfo *
17060 _clutter_actor_get_animation_info (ClutterActor *self)
17061 {
17062   GObject *obj = G_OBJECT (self);
17063   ClutterAnimationInfo *res;
17064
17065   res = g_object_get_qdata (obj, quark_actor_animation_info);
17066   if (res == NULL)
17067     {
17068       res = g_slice_new (ClutterAnimationInfo);
17069
17070       *res = default_animation_info;
17071
17072       g_object_set_qdata_full (obj, quark_actor_animation_info,
17073                                res,
17074                                clutter_animation_info_free);
17075     }
17076
17077   return res;
17078 }
17079
17080 ClutterTransition *
17081 _clutter_actor_get_transition (ClutterActor *actor,
17082                                GParamSpec   *pspec)
17083 {
17084   const ClutterAnimationInfo *info;
17085
17086   info = _clutter_actor_get_animation_info_or_defaults (actor);
17087
17088   if (info->transitions == NULL)
17089     return NULL;
17090
17091   return g_hash_table_lookup (info->transitions, pspec->name);
17092 }
17093
17094 typedef struct _TransitionClosure
17095 {
17096   ClutterActor *actor;
17097   ClutterTransition *transition;
17098   gchar *name;
17099   gulong completed_id;
17100 } TransitionClosure;
17101
17102 static void
17103 transition_closure_free (gpointer data)
17104 {
17105   if (G_LIKELY (data != NULL))
17106     {
17107       TransitionClosure *clos = data;
17108       ClutterTimeline *timeline;
17109
17110       timeline = CLUTTER_TIMELINE (clos->transition);
17111
17112       if (clutter_timeline_is_playing (timeline))
17113         clutter_timeline_stop (timeline);
17114
17115       g_signal_handler_disconnect (clos->transition, clos->completed_id);
17116
17117       g_object_unref (clos->transition);
17118       g_free (clos->name);
17119
17120       g_slice_free (TransitionClosure, clos);
17121     }
17122 }
17123
17124 static void
17125 on_transition_completed (ClutterTransition *transition,
17126                          TransitionClosure *clos)
17127 {
17128   ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
17129   ClutterActor *actor = clos->actor;
17130   ClutterAnimationInfo *info;
17131   gint n_repeats, cur_repeat;
17132
17133   info = _clutter_actor_get_animation_info (actor);
17134
17135   /* reset the caches used by animations */
17136   clutter_actor_store_content_box (actor, NULL);
17137
17138   /* ensure that we remove the transition only at the end
17139    * of its run; we emit ::completed for every repeat
17140    */
17141   n_repeats = clutter_timeline_get_repeat_count (timeline);
17142   cur_repeat = clutter_timeline_get_current_repeat (timeline);
17143
17144   if (cur_repeat == n_repeats)
17145     {
17146       if (clutter_transition_get_remove_on_complete (transition))
17147         {
17148           /* we take a reference here because removing the closure
17149            * will release the reference on the transition, and we
17150            * want the transition to survive the signal emission;
17151            * the master clock will release the last reference at
17152            * the end of the frame processing.
17153            */
17154           g_object_ref (transition);
17155           g_hash_table_remove (info->transitions, clos->name);
17156         }
17157     }
17158
17159   /* if it's the last transition then we clean up */
17160   if (g_hash_table_size (info->transitions) == 0)
17161     {
17162       g_hash_table_unref (info->transitions);
17163       info->transitions = NULL;
17164
17165       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17166                     _clutter_actor_get_debug_name (actor));
17167
17168       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17169     }
17170 }
17171
17172 void
17173 _clutter_actor_update_transition (ClutterActor *actor,
17174                                   GParamSpec   *pspec,
17175                                   ...)
17176 {
17177   TransitionClosure *clos;
17178   ClutterTimeline *timeline;
17179   ClutterInterval *interval;
17180   const ClutterAnimationInfo *info;
17181   va_list var_args;
17182   GType ptype;
17183   GValue initial = G_VALUE_INIT;
17184   GValue final = G_VALUE_INIT;
17185   char *error = NULL;
17186
17187   info = _clutter_actor_get_animation_info_or_defaults (actor);
17188
17189   if (info->transitions == NULL)
17190     return;
17191
17192   clos = g_hash_table_lookup (info->transitions, pspec->name);
17193   if (clos == NULL)
17194     return;
17195
17196   timeline = CLUTTER_TIMELINE (clos->transition);
17197
17198   va_start (var_args, pspec);
17199
17200   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17201
17202   g_value_init (&initial, ptype);
17203   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17204                                         pspec->name,
17205                                         &initial);
17206
17207   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17208   if (error != NULL)
17209     {
17210       g_critical ("%s: %s", G_STRLOC, error);
17211       g_free (error);
17212       goto out;
17213     }
17214
17215   interval = clutter_transition_get_interval (clos->transition);
17216   clutter_interval_set_initial_value (interval, &initial);
17217   clutter_interval_set_final_value (interval, &final);
17218
17219   /* if we're updating with an easing duration of zero milliseconds,
17220    * we just jump the timeline to the end and let it run its course
17221    */
17222   if (info->cur_state != NULL &&
17223       info->cur_state->easing_duration != 0)
17224     {
17225       guint cur_duration = clutter_timeline_get_duration (timeline);
17226       ClutterAnimationMode cur_mode =
17227         clutter_timeline_get_progress_mode (timeline);
17228
17229       if (cur_duration != info->cur_state->easing_duration)
17230         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17231
17232       if (cur_mode != info->cur_state->easing_mode)
17233         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17234
17235       clutter_timeline_rewind (timeline);
17236     }
17237   else
17238     {
17239       guint duration = clutter_timeline_get_duration (timeline);
17240
17241       clutter_timeline_advance (timeline, duration);
17242     }
17243
17244 out:
17245   g_value_unset (&initial);
17246   g_value_unset (&final);
17247
17248   va_end (var_args);
17249 }
17250
17251 /*< private >*
17252  * _clutter_actor_create_transition:
17253  * @actor: a #ClutterActor
17254  * @pspec: the property used for the transition
17255  * @...: initial and final state
17256  *
17257  * Creates a #ClutterTransition for the property represented by @pspec.
17258  *
17259  * Return value: a #ClutterTransition
17260  */
17261 ClutterTransition *
17262 _clutter_actor_create_transition (ClutterActor *actor,
17263                                   GParamSpec   *pspec,
17264                                   ...)
17265 {
17266   ClutterAnimationInfo *info;
17267   ClutterTransition *res = NULL;
17268   gboolean call_restore = FALSE;
17269   TransitionClosure *clos;
17270   va_list var_args;
17271
17272   info = _clutter_actor_get_animation_info (actor);
17273
17274   /* XXX - this will go away in 2.0
17275    *
17276    * if no state has been pushed, we assume that the easing state is
17277    * in "compatibility mode": all transitions have a duration of 0
17278    * msecs, which means that they happen immediately. in Clutter 2.0
17279    * this will turn into a g_assert(info->states != NULL), as every
17280    * actor will start with a predefined easing state
17281    */
17282   if (info->states == NULL)
17283     {
17284       clutter_actor_save_easing_state (actor);
17285       clutter_actor_set_easing_duration (actor, 0);
17286       call_restore = TRUE;
17287     }
17288
17289   if (info->transitions == NULL)
17290     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17291                                                NULL,
17292                                                transition_closure_free);
17293
17294   va_start (var_args, pspec);
17295
17296   clos = g_hash_table_lookup (info->transitions, pspec->name);
17297   if (clos == NULL)
17298     {
17299       ClutterTimeline *timeline;
17300       ClutterInterval *interval;
17301       GValue initial = G_VALUE_INIT;
17302       GValue final = G_VALUE_INIT;
17303       GType ptype;
17304       char *error;
17305
17306       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17307
17308       G_VALUE_COLLECT_INIT (&initial, ptype,
17309                             var_args, 0,
17310                             &error);
17311       if (error != NULL)
17312         {
17313           g_critical ("%s: %s", G_STRLOC, error);
17314           g_free (error);
17315           goto out;
17316         }
17317
17318       G_VALUE_COLLECT_INIT (&final, ptype,
17319                             var_args, 0,
17320                             &error);
17321
17322       if (error != NULL)
17323         {
17324           g_critical ("%s: %s", G_STRLOC, error);
17325           g_value_unset (&initial);
17326           g_free (error);
17327           goto out;
17328         }
17329
17330       /* if the current easing state has a duration of 0, then we don't
17331        * bother to create the transition, and we just set the final value
17332        * directly on the actor; we don't go through the Animatable
17333        * interface because we know we got here through an animatable
17334        * property.
17335        */
17336       if (info->cur_state->easing_duration == 0)
17337         {
17338           clutter_actor_set_animatable_property (actor,
17339                                                  pspec->param_id,
17340                                                  &final,
17341                                                  pspec);
17342           g_value_unset (&initial);
17343           g_value_unset (&final);
17344
17345           goto out;
17346         }
17347
17348       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17349
17350       g_value_unset (&initial);
17351       g_value_unset (&final);
17352
17353       res = clutter_property_transition_new (pspec->name);
17354
17355       clutter_transition_set_interval (res, interval);
17356       clutter_transition_set_remove_on_complete (res, TRUE);
17357
17358       timeline = CLUTTER_TIMELINE (res);
17359       clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17360       clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17361       clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17362
17363       /* this will start the transition as well */
17364       clutter_actor_add_transition (actor, pspec->name, res);
17365
17366       /* the actor now owns the transition */
17367       g_object_unref (res);
17368     }
17369   else
17370     res = clos->transition;
17371
17372 out:
17373   if (call_restore)
17374     clutter_actor_restore_easing_state (actor);
17375
17376   va_end (var_args);
17377
17378   return res;
17379 }
17380
17381 /**
17382  * clutter_actor_add_transition:
17383  * @self: a #ClutterActor
17384  * @name: the name of the transition to add
17385  * @transition: the #ClutterTransition to add
17386  *
17387  * Adds a @transition to the #ClutterActor's list of animations.
17388  *
17389  * The @name string is a per-actor unique identifier of the @transition: only
17390  * one #ClutterTransition can be associated to the specified @name.
17391  *
17392  * The @transition will be started once added.
17393  *
17394  * This function will take a reference on the @transition.
17395  *
17396  * This function is usually called implicitly when modifying an animatable
17397  * property.
17398  *
17399  * Since: 1.10
17400  */
17401 void
17402 clutter_actor_add_transition (ClutterActor      *self,
17403                               const char        *name,
17404                               ClutterTransition *transition)
17405 {
17406   ClutterTimeline *timeline;
17407   TransitionClosure *clos;
17408   ClutterAnimationInfo *info;
17409
17410   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17411   g_return_if_fail (name != NULL);
17412   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17413
17414   info = _clutter_actor_get_animation_info (self);
17415
17416   if (info->transitions == NULL)
17417     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17418                                                NULL,
17419                                                transition_closure_free);
17420
17421   if (g_hash_table_lookup (info->transitions, name) != NULL)
17422     {
17423       g_warning ("A transition with name '%s' already exists for "
17424                  "the actor '%s'",
17425                  name,
17426                  _clutter_actor_get_debug_name (self));
17427       return;
17428     }
17429
17430   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17431
17432   timeline = CLUTTER_TIMELINE (transition);
17433
17434   clos = g_slice_new (TransitionClosure);
17435   clos->actor = self;
17436   clos->transition = g_object_ref (transition);
17437   clos->name = g_strdup (name);
17438   clos->completed_id = g_signal_connect (timeline, "completed",
17439                                          G_CALLBACK (on_transition_completed),
17440                                          clos);
17441
17442   CLUTTER_NOTE (ANIMATION,
17443                 "Adding transition '%s' [%p] to actor '%s'",
17444                 clos->name,
17445                 clos->transition,
17446                 _clutter_actor_get_debug_name (self));
17447
17448   g_hash_table_insert (info->transitions, clos->name, clos);
17449   clutter_timeline_start (timeline);
17450 }
17451
17452 /**
17453  * clutter_actor_remove_transition:
17454  * @self: a #ClutterActor
17455  * @name: the name of the transition to remove
17456  *
17457  * Removes the transition stored inside a #ClutterActor using @name
17458  * identifier.
17459  *
17460  * If the transition is currently in progress, it will be stopped.
17461  *
17462  * This function releases the reference acquired when the transition
17463  * was added to the #ClutterActor.
17464  *
17465  * Since: 1.10
17466  */
17467 void
17468 clutter_actor_remove_transition (ClutterActor *self,
17469                                  const char   *name)
17470 {
17471   const ClutterAnimationInfo *info;
17472
17473   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17474   g_return_if_fail (name != NULL);
17475
17476   info = _clutter_actor_get_animation_info_or_defaults (self);
17477
17478   if (info->transitions == NULL)
17479     return;
17480
17481   g_hash_table_remove (info->transitions, name);
17482 }
17483
17484 /**
17485  * clutter_actor_remove_all_transitions:
17486  * @self: a #ClutterActor
17487  *
17488  * Removes all transitions associated to @self.
17489  *
17490  * Since: 1.10
17491  */
17492 void
17493 clutter_actor_remove_all_transitions (ClutterActor *self)
17494 {
17495   const ClutterAnimationInfo *info;
17496
17497   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17498
17499   info = _clutter_actor_get_animation_info_or_defaults (self);
17500   if (info->transitions == NULL)
17501     return;
17502
17503   g_hash_table_remove_all (info->transitions);
17504 }
17505
17506 /**
17507  * clutter_actor_set_easing_duration:
17508  * @self: a #ClutterActor
17509  * @msecs: the duration of the easing, or %NULL
17510  *
17511  * Sets the duration of the tweening for animatable properties
17512  * of @self for the current easing state.
17513  *
17514  * Since: 1.10
17515  */
17516 void
17517 clutter_actor_set_easing_duration (ClutterActor *self,
17518                                    guint         msecs)
17519 {
17520   ClutterAnimationInfo *info;
17521
17522   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17523
17524   info = _clutter_actor_get_animation_info (self);
17525
17526   if (info->cur_state == NULL)
17527     {
17528       g_warning ("You must call clutter_actor_save_easing_state() prior "
17529                  "to calling clutter_actor_set_easing_duration().");
17530       return;
17531     }
17532
17533   if (info->cur_state->easing_duration != msecs)
17534     info->cur_state->easing_duration = msecs;
17535 }
17536
17537 /**
17538  * clutter_actor_get_easing_duration:
17539  * @self: a #ClutterActor
17540  *
17541  * Retrieves the duration of the tweening for animatable
17542  * properties of @self for the current easing state.
17543  *
17544  * Return value: the duration of the tweening, in milliseconds
17545  *
17546  * Since: 1.10
17547  */
17548 guint
17549 clutter_actor_get_easing_duration (ClutterActor *self)
17550 {
17551   const ClutterAnimationInfo *info;
17552
17553   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17554
17555   info = _clutter_actor_get_animation_info_or_defaults (self);
17556
17557   if (info->cur_state != NULL)
17558     return info->cur_state->easing_duration;
17559
17560   return 0;
17561 }
17562
17563 /**
17564  * clutter_actor_set_easing_mode:
17565  * @self: a #ClutterActor
17566  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17567  *
17568  * Sets the easing mode for the tweening of animatable properties
17569  * of @self.
17570  *
17571  * Since: 1.10
17572  */
17573 void
17574 clutter_actor_set_easing_mode (ClutterActor         *self,
17575                                ClutterAnimationMode  mode)
17576 {
17577   ClutterAnimationInfo *info;
17578
17579   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17580   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17581   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17582
17583   info = _clutter_actor_get_animation_info (self);
17584
17585   if (info->cur_state == NULL)
17586     {
17587       g_warning ("You must call clutter_actor_save_easing_state() prior "
17588                  "to calling clutter_actor_set_easing_mode().");
17589       return;
17590     }
17591
17592   if (info->cur_state->easing_mode != mode)
17593     info->cur_state->easing_mode = mode;
17594 }
17595
17596 /**
17597  * clutter_actor_get_easing_mode:
17598  * @self: a #ClutterActor
17599  *
17600  * Retrieves the easing mode for the tweening of animatable properties
17601  * of @self for the current easing state.
17602  *
17603  * Return value: an easing mode
17604  *
17605  * Since: 1.10
17606  */
17607 ClutterAnimationMode
17608 clutter_actor_get_easing_mode (ClutterActor *self)
17609 {
17610   const ClutterAnimationInfo *info;
17611
17612   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17613
17614   info = _clutter_actor_get_animation_info_or_defaults (self);
17615
17616   if (info->cur_state != NULL)
17617     return info->cur_state->easing_mode;
17618
17619   return CLUTTER_EASE_OUT_CUBIC;
17620 }
17621
17622 /**
17623  * clutter_actor_set_easing_delay:
17624  * @self: a #ClutterActor
17625  * @msecs: the delay before the start of the tweening, in milliseconds
17626  *
17627  * Sets the delay that should be applied before tweening animatable
17628  * properties.
17629  *
17630  * Since: 1.10
17631  */
17632 void
17633 clutter_actor_set_easing_delay (ClutterActor *self,
17634                                 guint         msecs)
17635 {
17636   ClutterAnimationInfo *info;
17637
17638   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17639
17640   info = _clutter_actor_get_animation_info (self);
17641
17642   if (info->cur_state == NULL)
17643     {
17644       g_warning ("You must call clutter_actor_save_easing_state() prior "
17645                  "to calling clutter_actor_set_easing_delay().");
17646       return;
17647     }
17648
17649   if (info->cur_state->easing_delay != msecs)
17650     info->cur_state->easing_delay = msecs;
17651 }
17652
17653 /**
17654  * clutter_actor_get_easing_delay:
17655  * @self: a #ClutterActor
17656  *
17657  * Retrieves the delay that should be applied when tweening animatable
17658  * properties.
17659  *
17660  * Return value: a delay, in milliseconds
17661  *
17662  * Since: 1.10
17663  */
17664 guint
17665 clutter_actor_get_easing_delay (ClutterActor *self)
17666 {
17667   const ClutterAnimationInfo *info;
17668
17669   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17670
17671   info = _clutter_actor_get_animation_info_or_defaults (self);
17672
17673   if (info->cur_state != NULL)
17674     return info->cur_state->easing_delay;
17675
17676   return 0;
17677 }
17678
17679 /**
17680  * clutter_actor_get_transition:
17681  * @self: a #ClutterActor
17682  * @name: the name of the transition
17683  *
17684  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17685  * transition @name.
17686  *
17687  * Transitions created for animatable properties use the name of the
17688  * property itself, for instance the code below:
17689  *
17690  * |[
17691  *   clutter_actor_set_easing_duration (actor, 1000);
17692  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17693  *
17694  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17695  *   g_signal_connect (transition, "completed",
17696  *                     G_CALLBACK (on_transition_complete),
17697  *                     actor);
17698  * ]|
17699  *
17700  * will call the <function>on_transition_complete</function> callback when
17701  * the transition is complete.
17702  *
17703  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17704  *   was found to match the passed name; the returned instance is owned
17705  *   by Clutter and it should not be freed
17706  *
17707  * Since: 1.10
17708  */
17709 ClutterTransition *
17710 clutter_actor_get_transition (ClutterActor *self,
17711                               const char   *name)
17712 {
17713   TransitionClosure *clos;
17714   const ClutterAnimationInfo *info;
17715
17716   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17717   g_return_val_if_fail (name != NULL, NULL);
17718
17719   info = _clutter_actor_get_animation_info_or_defaults (self);
17720   if (info->transitions == NULL)
17721     return NULL;
17722
17723   clos = g_hash_table_lookup (info->transitions, name);
17724   if (clos == NULL)
17725     return NULL;
17726
17727   return clos->transition;
17728 }
17729
17730 /**
17731  * clutter_actor_save_easing_state:
17732  * @self: a #ClutterActor
17733  *
17734  * Saves the current easing state for animatable properties, and creates
17735  * a new state with the default values for easing mode and duration.
17736  *
17737  * Since: 1.10
17738  */
17739 void
17740 clutter_actor_save_easing_state (ClutterActor *self)
17741 {
17742   ClutterAnimationInfo *info;
17743   AState new_state;
17744
17745   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17746
17747   info = _clutter_actor_get_animation_info (self);
17748
17749   if (info->states == NULL)
17750     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17751
17752   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17753   new_state.easing_duration = 250;
17754   new_state.easing_delay = 0;
17755
17756   g_array_append_val (info->states, new_state);
17757
17758   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17759 }
17760
17761 /**
17762  * clutter_actor_restore_easing_state:
17763  * @self: a #ClutterActor
17764  *
17765  * Restores the easing state as it was prior to a call to
17766  * clutter_actor_save_easing_state().
17767  *
17768  * Since: 1.10
17769  */
17770 void
17771 clutter_actor_restore_easing_state (ClutterActor *self)
17772 {
17773   ClutterAnimationInfo *info;
17774
17775   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17776
17777   info = _clutter_actor_get_animation_info (self);
17778
17779   if (info->states == NULL)
17780     {
17781       g_critical ("The function clutter_actor_restore_easing_state() has "
17782                   "called without a previous call to "
17783                   "clutter_actor_save_easing_state().");
17784       return;
17785     }
17786
17787   g_array_remove_index (info->states, info->states->len - 1);
17788
17789   if (info->states->len > 0)
17790     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17791   else
17792     {
17793       g_array_unref (info->states);
17794       info->states = NULL;
17795       info->cur_state = NULL;
17796     }
17797 }
17798
17799 /**
17800  * clutter_actor_set_content:
17801  * @self: a #ClutterActor
17802  * @content: (allow-none): a #ClutterContent, or %NULL
17803  *
17804  * Sets the contents of a #ClutterActor.
17805  *
17806  * Since: 1.10
17807  */
17808 void
17809 clutter_actor_set_content (ClutterActor   *self,
17810                            ClutterContent *content)
17811 {
17812   ClutterActorPrivate *priv;
17813
17814   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17815   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17816
17817   priv = self->priv;
17818
17819   if (priv->content != NULL)
17820     {
17821       _clutter_content_detached (priv->content, self);
17822       g_clear_object (&priv->content);
17823     }
17824
17825   priv->content = content;
17826
17827   if (priv->content != NULL)
17828     {
17829       g_object_ref (priv->content);
17830       _clutter_content_attached (priv->content, self);
17831     }
17832
17833   /* given that the content is always painted within the allocation,
17834    * we only need to queue a redraw here
17835    */
17836   clutter_actor_queue_redraw (self);
17837
17838   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17839
17840   /* if the content gravity is not resize-fill, and the new content has a
17841    * different preferred size than the previous one, then the content box
17842    * may have been changed. since we compute that lazily, we just notify
17843    * here, and let whomever watches :content-box do whatever they need to
17844    * do.
17845    */
17846   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17847     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17848 }
17849
17850 /**
17851  * clutter_actor_get_content:
17852  * @self: a #ClutterActor
17853  *
17854  * Retrieves the contents of @self.
17855  *
17856  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17857  *   or %NULL if none was set
17858  *
17859  * Since: 1.10
17860  */
17861 ClutterContent *
17862 clutter_actor_get_content (ClutterActor *self)
17863 {
17864   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17865
17866   return self->priv->content;
17867 }
17868
17869 /**
17870  * clutter_actor_set_content_gravity:
17871  * @self: a #ClutterActor
17872  * @gravity: the #ClutterContentGravity
17873  *
17874  * Sets the gravity of the #ClutterContent used by @self.
17875  *
17876  * See the description of the #ClutterActor:content-gravity property for
17877  * more information.
17878  *
17879  * The #ClutterActor:content-gravity property is animatable.
17880  *
17881  * Since: 1.10
17882  */
17883 void
17884 clutter_actor_set_content_gravity (ClutterActor *self,
17885                                    ClutterContentGravity  gravity)
17886 {
17887   ClutterActorPrivate *priv;
17888
17889   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17890
17891   priv = self->priv;
17892
17893   if (priv->content_gravity == gravity)
17894     return;
17895
17896   priv->content_box_valid = FALSE;
17897
17898   if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17899     {
17900       ClutterActorBox from_box, to_box;
17901
17902       clutter_actor_get_content_box (self, &from_box);
17903
17904       priv->content_gravity = gravity;
17905
17906       clutter_actor_get_content_box (self, &to_box);
17907
17908       _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17909                                         &from_box,
17910                                         &to_box);
17911     }
17912   else
17913     {
17914       ClutterActorBox to_box;
17915
17916       priv->content_gravity = gravity;
17917
17918       clutter_actor_get_content_box (self, &to_box);
17919
17920       _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17921                                         &to_box);
17922     }
17923
17924   clutter_actor_queue_redraw (self);
17925
17926   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17927 }
17928
17929 /**
17930  * clutter_actor_get_content_gravity:
17931  * @self: a #ClutterActor
17932  *
17933  * Retrieves the content gravity as set using
17934  * clutter_actor_get_content_gravity().
17935  *
17936  * Return value: the content gravity
17937  *
17938  * Since: 1.10
17939  */
17940 ClutterContentGravity
17941 clutter_actor_get_content_gravity (ClutterActor *self)
17942 {
17943   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17944                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17945
17946   return self->priv->content_gravity;
17947 }
17948
17949 /**
17950  * clutter_actor_get_content_box:
17951  * @self: a #ClutterActor
17952  * @box: (out caller-allocates): the return location for the bounding
17953  *   box for the #ClutterContent
17954  *
17955  * Retrieves the bounding box for the #ClutterContent of @self.
17956  *
17957  * The bounding box is relative to the actor's allocation.
17958  *
17959  * If no #ClutterContent is set for @self, or if @self has not been
17960  * allocated yet, then the result is undefined.
17961  *
17962  * The content box is guaranteed to be, at most, as big as the allocation
17963  * of the #ClutterActor.
17964  *
17965  * If the #ClutterContent used by the actor has a preferred size, then
17966  * it is possible to modify the content box by using the
17967  * #ClutterActor:content-gravity property.
17968  *
17969  * Since: 1.10
17970  */
17971 void
17972 clutter_actor_get_content_box (ClutterActor    *self,
17973                                ClutterActorBox *box)
17974 {
17975   ClutterActorPrivate *priv;
17976   gfloat content_w, content_h;
17977   gfloat alloc_w, alloc_h;
17978
17979   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17980   g_return_if_fail (box != NULL);
17981
17982   priv = self->priv;
17983
17984   box->x1 = 0.f;
17985   box->y1 = 0.f;
17986   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17987   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17988
17989   if (priv->content_box_valid)
17990     {
17991       *box = priv->content_box;
17992       return;
17993     }
17994
17995   /* no need to do any more work */
17996   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17997     return;
17998
17999   if (priv->content == NULL)
18000     return;
18001
18002   /* if the content does not have a preferred size then there is
18003    * no point in computing the content box
18004    */
18005   if (!clutter_content_get_preferred_size (priv->content,
18006                                            &content_w,
18007                                            &content_h))
18008     return;
18009
18010   alloc_w = box->x2;
18011   alloc_h = box->y2;
18012
18013   switch (priv->content_gravity)
18014     {
18015     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
18016       box->x2 = box->x1 + MIN (content_w, alloc_w);
18017       box->y2 = box->y1 + MIN (content_h, alloc_h);
18018       break;
18019
18020     case CLUTTER_CONTENT_GRAVITY_TOP:
18021       if (alloc_w > content_w)
18022         {
18023           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18024           box->x2 = box->x1 + content_w;
18025         }
18026       box->y2 = box->y1 + MIN (content_h, alloc_h);
18027       break;
18028
18029     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
18030       if (alloc_w > content_w)
18031         {
18032           box->x1 += (alloc_w - content_w);
18033           box->x2 = box->x1 + content_w;
18034         }
18035       box->y2 = box->y1 + MIN (content_h, alloc_h);
18036       break;
18037
18038     case CLUTTER_CONTENT_GRAVITY_LEFT:
18039       box->x2 = box->x1 + MIN (content_w, alloc_w);
18040       if (alloc_h > content_h)
18041         {
18042           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18043           box->y2 = box->y1 + content_h;
18044         }
18045       break;
18046
18047     case CLUTTER_CONTENT_GRAVITY_CENTER:
18048       if (alloc_w > content_w)
18049         {
18050           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18051           box->x2 = box->x1 + content_w;
18052         }
18053       if (alloc_h > content_h)
18054         {
18055           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18056           box->y2 = box->y1 + content_h;
18057         }
18058       break;
18059
18060     case CLUTTER_CONTENT_GRAVITY_RIGHT:
18061       if (alloc_w > content_w)
18062         {
18063           box->x1 += (alloc_w - content_w);
18064           box->x2 = box->x1 + content_w;
18065         }
18066       if (alloc_h > content_h)
18067         {
18068           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18069           box->y2 = box->y1 + content_h;
18070         }
18071       break;
18072
18073     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18074       box->x2 = box->x1 + MIN (content_w, alloc_w);
18075       if (alloc_h > content_h)
18076         {
18077           box->y1 += (alloc_h - content_h);
18078           box->y2 = box->y1 + content_h;
18079         }
18080       break;
18081
18082     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18083       if (alloc_w > content_w)
18084         {
18085           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18086           box->x2 = box->x1 + content_w;
18087         }
18088       if (alloc_h > content_h)
18089         {
18090           box->y1 += (alloc_h - content_h);
18091           box->y2 = box->y1 + content_h;
18092         }
18093       break;
18094
18095     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18096       if (alloc_w > content_w)
18097         {
18098           box->x1 += (alloc_w - content_w);
18099           box->x2 = box->x1 + content_w;
18100         }
18101       if (alloc_h > content_h)
18102         {
18103           box->y1 += (alloc_h - content_h);
18104           box->y2 = box->y1 + content_h;
18105         }
18106       break;
18107
18108     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18109       g_assert_not_reached ();
18110       break;
18111
18112     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18113       {
18114         double r_c = content_w / content_h;
18115         double r_a = alloc_w / alloc_h;
18116
18117         if (r_c >= 1.0)
18118           {
18119             if (r_a >= 1.0)
18120               {
18121                 box->x1 = 0.f;
18122                 box->x2 = alloc_w;
18123
18124                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18125                 box->y2 = box->y1 + (alloc_w * r_c);
18126               }
18127             else
18128               {
18129                 box->y1 = 0.f;
18130                 box->y2 = alloc_h;
18131
18132                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18133                 box->x2 = box->x1 + (alloc_h * r_c);
18134               }
18135           }
18136         else
18137           {
18138             if (r_a >= 1.0)
18139               {
18140                 box->y1 = 0.f;
18141                 box->y2 = alloc_h;
18142
18143                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18144                 box->x2 = box->x1 + (alloc_h * r_c);
18145               }
18146             else
18147               {
18148                 box->x1 = 0.f;
18149                 box->x2 = alloc_w;
18150
18151                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18152                 box->y2 = box->y1 + (alloc_w * r_c);
18153               }
18154           }
18155       }
18156       break;
18157     }
18158 }
18159
18160 /**
18161  * clutter_actor_set_content_scaling_filters:
18162  * @self: a #ClutterActor
18163  * @min_filter: the minification filter for the content
18164  * @mag_filter: the magnification filter for the content
18165  *
18166  * Sets the minification and magnification filter to be applied when
18167  * scaling the #ClutterActor:content of a #ClutterActor.
18168  *
18169  * The #ClutterActor:minification-filter will be used when reducing
18170  * the size of the content; the #ClutterActor:magnification-filter
18171  * will be used when increasing the size of the content.
18172  *
18173  * Since: 1.10
18174  */
18175 void
18176 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18177                                            ClutterScalingFilter  min_filter,
18178                                            ClutterScalingFilter  mag_filter)
18179 {
18180   ClutterActorPrivate *priv;
18181   gboolean changed;
18182   GObject *obj;
18183
18184   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18185
18186   priv = self->priv;
18187   obj = G_OBJECT (self);
18188
18189   g_object_freeze_notify (obj);
18190
18191   changed = FALSE;
18192
18193   if (priv->min_filter != min_filter)
18194     {
18195       priv->min_filter = min_filter;
18196       changed = TRUE;
18197
18198       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18199     }
18200
18201   if (priv->mag_filter != mag_filter)
18202     {
18203       priv->mag_filter = mag_filter;
18204       changed = TRUE;
18205
18206       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18207     }
18208
18209   if (changed)
18210     clutter_actor_queue_redraw (self);
18211
18212   g_object_thaw_notify (obj);
18213 }
18214
18215 /**
18216  * clutter_actor_get_content_scaling_filters:
18217  * @self: a #ClutterActor
18218  * @min_filter: (out) (allow-none): return location for the minification
18219  *   filter, or %NULL
18220  * @mag_filter: (out) (allow-none): return location for the magnification
18221  *   filter, or %NULL
18222  *
18223  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18224  *
18225  * Since: 1.10
18226  */
18227 void
18228 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18229                                            ClutterScalingFilter *min_filter,
18230                                            ClutterScalingFilter *mag_filter)
18231 {
18232   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18233
18234   if (min_filter != NULL)
18235     *min_filter = self->priv->min_filter;
18236
18237   if (mag_filter != NULL)
18238     *mag_filter = self->priv->mag_filter;
18239 }
18240
18241 /*
18242  * clutter_actor_queue_compute_expand:
18243  * @self: a #ClutterActor
18244  *
18245  * Invalidates the needs_x_expand and needs_y_expand flags on @self
18246  * and its parents up to the top-level actor.
18247  *
18248  * This function also queues a relayout if anything changed.
18249  */
18250 static inline void
18251 clutter_actor_queue_compute_expand (ClutterActor *self)
18252 {
18253   ClutterActor *parent;
18254   gboolean changed;
18255
18256   if (self->priv->needs_compute_expand)
18257     return;
18258
18259   changed = FALSE;
18260   parent = self;
18261   while (parent != NULL)
18262     {
18263       if (!parent->priv->needs_compute_expand)
18264         {
18265           parent->priv->needs_compute_expand = TRUE;
18266           changed = TRUE;
18267         }
18268
18269       parent = parent->priv->parent;
18270     }
18271
18272   if (changed)
18273     clutter_actor_queue_relayout (self);
18274 }
18275
18276 /**
18277  * clutter_actor_set_x_expand:
18278  * @self: a #ClutterActor
18279  * @expand: whether the actor should expand horizontally
18280  *
18281  * Sets whether a #ClutterActor should expand horizontally; this means
18282  * that layout manager should allocate extra space for the actor, if
18283  * possible.
18284  *
18285  * Setting an actor to expand will also make all its parent expand, so
18286  * that it's possible to build an actor tree and only set this flag on
18287  * its leaves and not on every single actor.
18288  *
18289  * Since: 1.12
18290  */
18291 void
18292 clutter_actor_set_x_expand (ClutterActor *self,
18293                             gboolean      expand)
18294 {
18295   ClutterLayoutInfo *info;
18296
18297   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18298
18299   expand = !!expand;
18300
18301   info = _clutter_actor_get_layout_info (self);
18302   if (info->x_expand != expand)
18303     {
18304       info->x_expand = expand;
18305
18306       self->priv->x_expand_set = TRUE;
18307
18308       clutter_actor_queue_compute_expand (self);
18309
18310       g_object_notify_by_pspec (G_OBJECT (self),
18311                                 obj_props[PROP_X_EXPAND]);
18312     }
18313 }
18314
18315 /**
18316  * clutter_actor_get_x_expand:
18317  * @self: a #ClutterActor
18318  *
18319  * Retrieves the value set with clutter_actor_set_x_expand().
18320  *
18321  * See also: clutter_actor_needs_x_expand()
18322  *
18323  * Return value: %TRUE if the actor has been set to expand
18324  *
18325  * Since: 1.12
18326  */
18327 gboolean
18328 clutter_actor_get_x_expand (ClutterActor *self)
18329 {
18330   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18331
18332   return _clutter_actor_get_layout_info_or_defaults (self)->x_expand;
18333 }
18334
18335 /**
18336  * clutter_actor_set_y_expand:
18337  * @self: a #ClutterActor
18338  * @expand: whether the actor should expand vertically
18339  *
18340  * Sets whether a #ClutterActor should expand horizontally; this means
18341  * that layout manager should allocate extra space for the actor, if
18342  * possible.
18343  *
18344  * Setting an actor to expand will also make all its parent expand, so
18345  * that it's possible to build an actor tree and only set this flag on
18346  * its leaves and not on every single actor.
18347  *
18348  * Since: 1.12
18349  */
18350 void
18351 clutter_actor_set_y_expand (ClutterActor *self,
18352                             gboolean      expand)
18353 {
18354   ClutterLayoutInfo *info;
18355
18356   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18357
18358   expand = !!expand;
18359
18360   info = _clutter_actor_get_layout_info (self);
18361   if (info->y_expand != expand)
18362     {
18363       info->y_expand = expand;
18364
18365       self->priv->y_expand_set = TRUE;
18366
18367       clutter_actor_queue_compute_expand (self);
18368
18369       g_object_notify_by_pspec (G_OBJECT (self),
18370                                 obj_props[PROP_Y_EXPAND]);
18371     }
18372 }
18373
18374 /**
18375  * clutter_actor_get_y_expand:
18376  * @self: a #ClutterActor
18377  *
18378  * Retrieves the value set with clutter_actor_set_y_expand().
18379  *
18380  * See also: clutter_actor_needs_y_expand()
18381  *
18382  * Return value: %TRUE if the actor has been set to expand
18383  *
18384  * Since: 1.12
18385  */
18386 gboolean
18387 clutter_actor_get_y_expand (ClutterActor *self)
18388 {
18389   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18390
18391   return _clutter_actor_get_layout_info_or_defaults (self)->y_expand;
18392 }
18393
18394 static void
18395 clutter_actor_compute_expand_recursive (ClutterActor *self,
18396                                         gboolean     *x_expand_p,
18397                                         gboolean     *y_expand_p)
18398 {
18399   ClutterActorIter iter;
18400   ClutterActor *child;
18401   gboolean x_expand, y_expand;
18402
18403   x_expand = y_expand = FALSE;
18404
18405   clutter_actor_iter_init (&iter, self);
18406   while (clutter_actor_iter_next (&iter, &child))
18407     {
18408       x_expand = x_expand || clutter_actor_needs_x_expand (child);
18409       y_expand = y_expand || clutter_actor_needs_y_expand (child);
18410     }
18411
18412   *x_expand_p = x_expand;
18413   *y_expand_p = y_expand;
18414 }
18415
18416 static void
18417 clutter_actor_compute_expand (ClutterActor *self)
18418 {
18419   if (self->priv->needs_compute_expand)
18420     {
18421       const ClutterLayoutInfo *info;
18422       gboolean x_expand, y_expand;
18423
18424       info = _clutter_actor_get_layout_info_or_defaults (self);
18425
18426       if (self->priv->x_expand_set)
18427         x_expand = info->x_expand;
18428       else
18429         x_expand = FALSE;
18430
18431       if (self->priv->y_expand_set)
18432         y_expand = info->y_expand;
18433       else
18434         y_expand = FALSE;
18435
18436       /* we don't need to recurse down to the children if the
18437        * actor has been forcibly set to expand
18438        */
18439       if (!(self->priv->x_expand_set && self->priv->y_expand_set))
18440         {
18441           if (self->priv->n_children != 0)
18442             {
18443               gboolean *x_expand_p, *y_expand_p;
18444               gboolean ignored = FALSE;
18445
18446               x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand;
18447               y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand;
18448
18449               clutter_actor_compute_expand_recursive (self,
18450                                                       x_expand_p,
18451                                                       y_expand_p);
18452             }
18453         }
18454
18455       self->priv->needs_compute_expand = FALSE;
18456       self->priv->needs_x_expand = (x_expand != FALSE);
18457       self->priv->needs_y_expand = (y_expand != FALSE);
18458     }
18459 }
18460
18461 /**
18462  * clutter_actor_needs_x_expand:
18463  * @self: a #ClutterActor
18464  *
18465  * Checks whether an actor, or any of its children, is set to expand
18466  * horizontally.
18467  *
18468  * This function should only be called by layout managers that can
18469  * assign extra space to their children.
18470  *
18471  * If you want to know whether the actor was explicitly set to expand,
18472  * use clutter_actor_get_y_expand().
18473  *
18474  * Return value: %TRUE if the actor should expand
18475  *
18476  * Since: 1.12
18477  */
18478 gboolean
18479 clutter_actor_needs_x_expand (ClutterActor *self)
18480 {
18481   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18482
18483   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18484     return FALSE;
18485
18486   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18487     return FALSE;
18488
18489   clutter_actor_compute_expand (self);
18490
18491   return self->priv->needs_x_expand;
18492 }
18493
18494 /**
18495  * clutter_actor_needs_y_expand:
18496  * @self: a #ClutterActor
18497  *
18498  * Checks whether an actor, or any of its children, is set to expand
18499  * vertically.
18500  *
18501  * This function should only be called by layout managers that can
18502  * assign extra space to their children.
18503  *
18504  * If you want to know whether the actor was explicitly set to expand,
18505  * use clutter_actor_get_y_expand().
18506  *
18507  * Return value: %TRUE if the actor should expand
18508  *
18509  * Since: 1.12
18510  */
18511 gboolean
18512 clutter_actor_needs_y_expand (ClutterActor *self)
18513 {
18514   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18515
18516   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18517     return FALSE;
18518
18519   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18520     return FALSE;
18521
18522   clutter_actor_compute_expand (self);
18523
18524   return self->priv->needs_x_expand;
18525 }