docs: Annotation fixes
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010, 2011, 2012 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: The basic element of the scene graph 
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-painting">
119  *   <title>Painting an actor</title>
120  *   <para>There are three ways to paint an actor:</para>
121  *   <itemizedlist>
122  *     <listitem><para>set a delegate #ClutterContent as the value for the
123  *     #ClutterActor:content property of the actor;</para></listitem>
124  *     <listitem><para>subclass #ClutterActor and override the
125  *     #ClutterActorClass.paint_node() virtual function;</para></listitem>
126  *     <listitem><para>subclass #ClutterActor and override the
127  *     #ClutterActorClass.paint() virtual function.</para></listitem>
128  *   </itemizedlist>
129  *   <formalpara>
130  *     <title>Setting the Content property</title>
131  *     <para>A #ClutterContent is a delegate object that takes over the
132  *     painting operation of one, or more actors. The #ClutterContent
133  *     painting will be performed on top of the #ClutterActor:background-color
134  *     of the actor, and before calling the #ClutterActorClass.paint_node()
135  *     virtual function.</para>
136  *     <informalexample><programlisting>
137  * ClutterActor *actor = clutter_actor_new ();
138  *
139  * /&ast; set the bounding box &ast;/
140  * clutter_actor_set_position (actor, 50, 50);
141  * clutter_actor_set_size (actor, 100, 100);
142  *
143  * /&ast; set the content; the image_content variable is set elsewhere &ast;/
144  * clutter_actor_set_content (actor, image_content);
145  *     </programlisting></informalexample>
146  *   </formalpara>
147  *   <formalpara>
148  *     <title>Overriding the paint_node virtual function</title>
149  *     <para>The #ClutterActorClass.paint_node() virtual function is invoked
150  *     whenever an actor needs to be painted. The implementation of the
151  *     virtual function must only paint the contents of the actor itself,
152  *     and not the contents of its children, if the actor has any.</para>
153  *     <para>The #ClutterPaintNode passed to the virtual function is the
154  *     local root of the render tree; any node added to it will be
155  *     rendered at the correct position, as defined by the actor's
156  *     #ClutterActor:allocation.</para>
157  *     <informalexample><programlisting>
158  * static void
159  * my_actor_paint_node (ClutterActor     *actor,
160  *                      ClutterPaintNode *root)
161  * {
162  *   ClutterPaintNode *node;
163  *   ClutterActorBox box;
164  *
165  *   /&ast; where the content of the actor should be painted &ast;/
166  *   clutter_actor_get_allocation_box (actor, &box);
167  *
168  *   /&ast; the cogl_texture variable is set elsewhere &ast;/
169  *   node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170  *                                    CLUTTER_SCALING_FILTER_TRILINEAR,
171  *                                    CLUTTER_SCALING_FILTER_LINEAR);
172  *
173  *   /&ast; paint the content of the node using the allocation &ast;/
174  *   clutter_paint_node_add_rectangle (node, &box);
175  *
176  *   /&ast; add the node, and transfer ownership &ast;/
177  *   clutter_paint_node_add_child (root, node);
178  *   clutter_paint_node_unref (node);
179  * }
180  *     </programlisting></informalexample>
181  *   </formalpara>
182  *   <formalpara>
183  *     <title>Overriding the paint virtual function</title>
184  *     <para>The #ClutterActorClass.paint() virtual function is invoked
185  *     when the #ClutterActor::paint signal is emitted, and after the other
186  *     signal handlers have been invoked. Overriding the paint virtual
187  *     function gives total control to the paint sequence of the actor
188  *     itself, including the children of the actor, if any.</para>
189  *     <warning><para>It is strongly discouraged to override the
190  *     #ClutterActorClass.paint() virtual function, as well as connecting
191  *     to the #ClutterActor::paint signal. These hooks into the paint
192  *     sequence are considered legacy, and will be removed when the Clutter
193  *     API changes.</para></warning>
194  *   </formalpara>
195  * </refsect2>
196  *
197  * <refsect2 id="ClutterActor-events">
198  *   <title>Handling events on an actor</title>
199  *   <para>A #ClutterActor can receive and handle input device events, for
200  *   instance pointer events and key events, as long as its
201  *   #ClutterActor:reactive property is set to %TRUE.</para>
202  *   <para>Once an actor has been determined to be the source of an event,
203  *   Clutter will traverse the scene graph from the top-level actor towards the
204  *   event source, emitting the #ClutterActor::captured-event signal on each
205  *   ancestor until it reaches the source; this phase is also called
206  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
207  *   stopped, the graph is walked backwards, from the source actor to the
208  *   top-level, and the #ClutterActor::event signal, along with other event
209  *   signals if needed, is emitted; this phase is also called <emphasis>the
210  *   bubble phase</emphasis>. At any point of the signal emission, signal
211  *   handlers can stop the propagation through the scene graph by returning
212  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
214  * </refsect2>
215  *
216  * <refsect2 id="ClutterActor-animation">
217  *   <title>Animation</title>
218  *   <para>Animation is a core concept of modern user interfaces; Clutter
219  *   provides a complete and powerful animation framework that automatically
220  *   tweens the actor's state without requiring direct, frame by frame
221  *   manipulation from your application code.</para>
222  *   <formalpara>
223  *     <title>Implicit animations</title>
224  *     <para>The implicit animation model of Clutter assumes that all the
225  *     changes in an actor state should be gradual and asynchronous; Clutter
226  *     will automatically transition an actor's property change between the
227  *     current state and the desired one without manual intervention.</para>
228  *     <para>By default, in the 1.0 API series, the transition happens with
229  *     a duration of zero milliseconds, and the implicit animation is an
230  *     opt in feature to retain backwards compatibility. In order to enable
231  *     implicit animations, it is necessary to change the easing state of
232  *     an actor by using clutter_actor_save_easing_state():</para>
233  *     <informalexample><programlisting>
234  * /&ast; assume that the actor is currently positioned at (100, 100) &ast;/
235  * clutter_actor_save_easing_state (actor);
236  * clutter_actor_set_position (actor, 500, 500);
237  * clutter_actor_restore_easing_state (actor);
238  *     </programlisting></informalexample>
239  *     <para>The example above will trigger an implicit animation of the
240  *     actor between its current position to a new position.</para>
241  *     <para>It is possible to animate multiple properties of an actor
242  *     at the same time, and you can animate multiple actors at the same
243  *     time as well, for instance:</para>
244  *     <informalexample><programlisting>
245  * /&ast; animate the actor's opacity and depth &ast;/
246  * clutter_actor_save_easing_state (actor);
247  * clutter_actor_set_opacity (actor, 0);
248  * clutter_actor_set_depth (actor, -100);
249  * clutter_actor_restore_easing_state (actor);
250  *
251  * /&ast; animate another actor's opacity &ast;/
252  * clutter_actor_save_easing_state (another_actor);
253  * clutter_actor_set_opacity (another_actor, 255);
254  * clutter_actor_set_depth (another_actor, 100);
255  * clutter_actor_restore_easing_state (another_actor);
256  *     </programlisting></informalexample>
257  *     <para>Implicit animations use a default duration of 250 milliseconds,
258  *     and a default easing mode of %CLUTTER_EASE_OUT_CUBIC, unless you call
259  *     clutter_actor_set_easing_mode() and clutter_actor_set_easing_duration()
260  *     after changing the easing state of the actor.</para>
261  *     <para>It is important to note that if you modify the state on an
262  *     animatable property while a transition is in flight, the transition's
263  *     final value will be updated, as well as its duration and progress
264  *     mode by using the current easing state; for instance, in the following
265  *     example:</para>
266  *     <informalexample><programlisting>
267  * clutter_actor_save_easing_state (actor);
268  * clutter_actor_set_x (actor, 200);
269  * clutter_actor_restore_easing_state (actor);
270  *
271  * clutter_actor_save_easing_state (actor);
272  * clutter_actor_set_x (actor, 100);
273  * clutter_actor_restore_easing_state (actor);
274  *     </programlisting></informalexample>
275  *     <para>the first call to clutter_actor_set_x() will begin a transition
276  *     of the #ClutterActor:x property to the value of 200; the second call
277  *     to clutter_actor_set_x() will change the transition's final value to
278  *     100.</para>
279  *     <para>It is possible to retrieve the #ClutterTransition used by the
280  *     animatable properties by using clutter_actor_get_transition() and using
281  *     the property name as the transition name.</para>
282  *   </formalpara>
283  *   <formalpara>
284  *     <title>Explicit animations</title>
285  *     <para>The explicit animation model supported by Clutter requires that
286  *     you create a #ClutterTransition object, and set the initial and
287  *     final values. The transition will not start unless you add it to the
288  *     #ClutterActor.</para>
289  *     <informalexample><programlisting>
290  * ClutterTransition *transition;
291  *
292  * transition = clutter_property_transition_new ("opacity");
293  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000);
294  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
295  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
296  * clutter_transition_set_from (transition, G_TYPE_UINT, 255);
297  * clutter_transition_set_to (transition, G_TYPE_UINT, 0);
298  *
299  * clutter_actor_add_transition (actor, "animate-opacity", transition);
300  *     </programlisting></informalexample>
301  *     <para>The example above will animate the #ClutterActor:opacity property
302  *     of an actor between fully opaque and fully transparent, and back, over
303  *     a span of 3 seconds. The animation does not begin until it is added to
304  *     the actor.</para>
305  *     <para>The explicit animation API should also be used when using custom
306  *     animatable properties for #ClutterAction, #ClutterConstraint, and
307  *     #ClutterEffect instances associated to an actor; see the section on
308  *     <ulink linkend="ClutterActor-custom-animatable-properties">custom
309  *     animatable properties below</ulink> for an example.</para>
310  *     <para>Finally, explicit animations are useful for creating animations
311  *     that run continuously, for instance:</para>
312  *     <informalexample><programlisting>
313  * /&ast; this animation will pulse the actor's opacity continuously &ast;/
314  * ClutterTransition *transition;
315  * ClutterInterval *interval;
316  *
317  * transition = clutter_property_transition_new ("opacity");
318  *
319  * /&ast; we want to animate the opacity between 0 and 255 &ast;/
320  * clutter_transition_set_from (transition, G_TYPE_UINT, 0);
321  * clutter_transition_set_to (transition, G_TYPE_UINT, 255);
322  *
323  * /&ast; over a one second duration, running an infinite amount of times &ast;/
324  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
325  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
326  *
327  * /&ast; we want to fade in and out, so we need to auto-reverse the transition &ast;/
328  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
329  *
330  * /&ast; and we want to use an easing function that eases both in and out &ast;/
331  * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
332  *                                     CLUTTER_EASE_IN_OUT_CUBIC);
333  *
334  * /&ast; add the transition to the desired actor; this will
335  *  &ast; start the animation.
336  *  &ast;/
337  * clutter_actor_add_transition (actor, "opacityAnimation", transition);
338  *     </programlisting></informalexample>
339  *   </formalpara>
340  * </refsect2>
341  *
342  * <refsect2 id="ClutterActor-subclassing">
343  *   <title>Implementing an actor</title>
344  *   <para>Careful consideration should be given when deciding to implement
345  *   a #ClutterActor sub-class. It is generally recommended to implement a
346  *   sub-class of #ClutterActor only for actors that should be used as leaf
347  *   nodes of a scene graph.</para>
348  *   <para>If your actor should be painted in a custom way, you should
349  *   override the #ClutterActor::paint signal class handler. You can either
350  *   opt to chain up to the parent class implementation or decide to fully
351  *   override the default paint implementation; Clutter will set up the
352  *   transformations and clip regions prior to emitting the #ClutterActor::paint
353  *   signal.</para>
354  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
355  *   #ClutterActorClass.get_preferred_height() virtual functions it is
356  *   possible to change or provide the preferred size of an actor; similarly,
357  *   by overriding the #ClutterActorClass.allocate() virtual function it is
358  *   possible to control the layout of the children of an actor. Make sure to
359  *   always chain up to the parent implementation of the
360  *   #ClutterActorClass.allocate() virtual function.</para>
361  *   <para>In general, it is strongly encouraged to use delegation and
362  *   composition instead of direct subclassing.</para>
363  * </refsect2>
364  *
365  * <refsect2 id="ClutterActor-script">
366  *   <title>ClutterActor custom properties for #ClutterScript</title>
367  *   <para>#ClutterActor defines a custom "rotation" property which
368  *   allows a short-hand description of the rotations to be applied
369  *   to an actor.</para>
370  *   <para>The syntax of the "rotation" property is the following:</para>
371  *   <informalexample>
372  *     <programlisting>
373  * "rotation" : [
374  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
375  * ]
376  *     </programlisting>
377  *   </informalexample>
378  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
379  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
380  *   floating point value representing the rotation angle on the given axis,
381  *   in degrees.</para>
382  *   <para>The <emphasis>center</emphasis> array is optional, and if present
383  *   it must contain the center of rotation as described by two coordinates:
384  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
385  *   "z-axis".</para>
386  *   <para>#ClutterActor will also parse every positional and dimensional
387  *   property defined as a string through clutter_units_from_string(); you
388  *   should read the documentation for the #ClutterUnits parser format for
389  *   the valid units and syntax.</para>
390  * </refsect2>
391  *
392  * <refsect2 id="ClutterActor-custom-animatable-properties">
393  *   <title>Custom animatable properties</title>
394  *   <para>#ClutterActor allows accessing properties of #ClutterAction,
395  *   #ClutterEffect, and #ClutterConstraint instances associated to an actor
396  *   instance for animation purposes.</para>
397  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
398  *   property it is necessary to set the #ClutterActorMeta:name property on the
399  *   given action or constraint.</para>
400  *   <para>The property can be accessed using the following syntax:</para>
401  *   <informalexample>
402  *     <programlisting>
403  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
404  *     </programlisting>
405  *   </informalexample>
406  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
407  *   <para>The <emphasis>section</emphasis> fragment can be one between
408  *   "actions", "constraints" and "effects".</para>
409  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
410  *   action or constraint, as specified by the #ClutterActorMeta:name
411  *   property.</para>
412  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
413  *   action or constraint property to be animated.</para>
414  *   <para>The example below animates a #ClutterBindConstraint applied to an
415  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
416  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
417  *   its initial state is overlapping the actor to which is bound to.</para>
418  *   <informalexample><programlisting>
419  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
420  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
421  * clutter_actor_add_constraint (rect, constraint);
422  *
423  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
424  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
425  * clutter_actor_add_constraint (rect, constraint);
426  *
427  * clutter_actor_set_reactive (origin, TRUE);
428  *
429  * g_signal_connect (origin, "button-press-event",
430  *                   G_CALLBACK (on_button_press),
431  *                   rect);
432  *   </programlisting></informalexample>
433  *   <para>On button press, the rectangle "slides" from behind the actor to
434  *   which is bound to, using the #ClutterBindConstraint:offset property to
435  *   achieve the effect:</para>
436  *   <informalexample><programlisting>
437  * gboolean
438  * on_button_press (ClutterActor *origin,
439  *                  ClutterEvent *event,
440  *                  ClutterActor *rect)
441  * {
442  *   ClutterTransition *transition;
443  *   ClutterInterval *interval;
444  *
445  *   /&ast; the offset that we want to apply; this will make the actor
446  *    &ast; slide in from behind the origin and rest at the right of
447  *    &ast; the origin, plus a padding value.
448  *    &ast;/
449  *   float new_offset = clutter_actor_get_width (origin) + h_padding;
450  *
451  *   /&ast; the property we wish to animate; the "@constraints" section
452  *    &ast; tells Clutter to check inside the constraints associated
453  *    &ast; with the actor; the "bind-x" section is the name of the
454  *    &ast; constraint; and the "offset" is the name of the property
455  *    &ast; on the constraint.
456  *    &ast;/
457  *   const char *prop = "@constraints.bind-x.offset";
458  *
459  *   /&ast; create a new transition for the given property &ast;/
460  *   transition = clutter_property_transition_new (prop);
461  *
462  *   /&ast; set the easing mode and duration &ast;/
463  *   clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
464  *                                       CLUTTER_EASE_OUT_CUBIC);
465  *   clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
466  *
467  *   /&ast; create the interval with the initial and final values &ast;/
468  *   interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
469  *   clutter_transition_set_interval (transition, interval);
470  *
471  *   /&ast; add the transition to the actor; this causes the animation
472  *    &ast; to start. the name "offsetAnimation" can be used to retrieve
473  *    &ast; the transition later.
474  *    &ast;/
475  *   clutter_actor_add_transition (rect, "offsetAnimation", transition);
476  *
477  *   /&ast; we handled the event &ast;/
478  *   return CLUTTER_EVENT_STOP;
479  * }
480  *   </programlisting></informalexample>
481  * </refsect2>
482  */
483
484 /**
485  * CLUTTER_ACTOR_IS_MAPPED:
486  * @a: a #ClutterActor
487  *
488  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
489  *
490  * The mapped state is set when the actor is visible and all its parents up
491  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
492  *
493  * This check can be used to see if an actor is going to be painted, as only
494  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
495  *
496  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
497  * not be checked directly; instead, the recommended usage is to connect a
498  * handler on the #GObject::notify signal for the #ClutterActor:mapped
499  * property of #ClutterActor, and check the presence of
500  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
501  *
502  * It is also important to note that Clutter may delay the changes of
503  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
504  * limitations, or during the reparenting of an actor, to optimize
505  * unnecessary (and potentially expensive) state changes.
506  *
507  * Since: 0.2
508  */
509
510 /**
511  * CLUTTER_ACTOR_IS_REALIZED:
512  * @a: a #ClutterActor
513  *
514  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
515  *
516  * The realized state has an actor-dependant interpretation. If an
517  * actor wants to delay allocating resources until it is attached to a
518  * stage, it may use the realize state to do so. However it is
519  * perfectly acceptable for an actor to allocate Cogl resources before
520  * being realized because there is only one drawing context used by Clutter
521  * so any resources will work on any stage.  If an actor is mapped it
522  * must also be realized, but an actor can be realized and unmapped
523  * (this is so hiding an actor temporarily doesn't do an expensive
524  * unrealize/realize).
525  *
526  * To be realized an actor must be inside a stage, and all its parents
527  * must be realized.
528  *
529  * Since: 0.2
530  */
531
532 /**
533  * CLUTTER_ACTOR_IS_VISIBLE:
534  * @a: a #ClutterActor
535  *
536  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
537  * Equivalent to the ClutterActor::visible object property.
538  *
539  * Note that an actor is only painted onscreen if it's mapped, which
540  * means it's visible, and all its parents are visible, and one of the
541  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
542  *
543  * Since: 0.2
544  */
545
546 /**
547  * CLUTTER_ACTOR_IS_REACTIVE:
548  * @a: a #ClutterActor
549  *
550  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
551  *
552  * Only reactive actors will receive event-related signals.
553  *
554  * Since: 0.6
555  */
556
557 #ifdef HAVE_CONFIG_H
558 #include "config.h"
559 #endif
560
561 #include <math.h>
562
563 #include <gobject/gvaluecollector.h>
564
565 #include <cogl/cogl.h>
566
567 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
568 #define CLUTTER_ENABLE_EXPERIMENTAL_API
569
570 #include "clutter-actor-private.h"
571
572 #include "clutter-action.h"
573 #include "clutter-actor-meta-private.h"
574 #include "clutter-animatable.h"
575 #include "clutter-color-static.h"
576 #include "clutter-color.h"
577 #include "clutter-constraint.h"
578 #include "clutter-container.h"
579 #include "clutter-content-private.h"
580 #include "clutter-debug.h"
581 #include "clutter-effect-private.h"
582 #include "clutter-enum-types.h"
583 #include "clutter-fixed-layout.h"
584 #include "clutter-flatten-effect.h"
585 #include "clutter-interval.h"
586 #include "clutter-main.h"
587 #include "clutter-marshal.h"
588 #include "clutter-paint-nodes.h"
589 #include "clutter-paint-node-private.h"
590 #include "clutter-paint-volume-private.h"
591 #include "clutter-private.h"
592 #include "clutter-profile.h"
593 #include "clutter-property-transition.h"
594 #include "clutter-scriptable.h"
595 #include "clutter-script-private.h"
596 #include "clutter-stage-private.h"
597 #include "clutter-timeline.h"
598 #include "clutter-transition.h"
599 #include "clutter-units.h"
600
601 #include "deprecated/clutter-actor.h"
602 #include "deprecated/clutter-behaviour.h"
603 #include "deprecated/clutter-container.h"
604
605 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
606 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
607
608 /* Internal enum used to control mapped state update.  This is a hint
609  * which indicates when to do something other than just enforce
610  * invariants.
611  */
612 typedef enum {
613   MAP_STATE_CHECK,           /* just enforce invariants. */
614   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
615                               * used when about to unparent.
616                               */
617   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
618                               * used to set mapped on toplevels.
619                               */
620   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
621                               * used just before unmapping parent.
622                               */
623 } MapStateChange;
624
625 /* 3 entries should be a good compromise, few layout managers
626  * will ask for 3 different preferred size in each allocation cycle */
627 #define N_CACHED_SIZE_REQUESTS 3
628
629 struct _ClutterActorPrivate
630 {
631   /* request mode */
632   ClutterRequestMode request_mode;
633
634   /* our cached size requests for different width / height */
635   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
636   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
637
638   /* An age of 0 means the entry is not set */
639   guint cached_height_age;
640   guint cached_width_age;
641
642   /* the bounding box of the actor, relative to the parent's
643    * allocation
644    */
645   ClutterActorBox allocation;
646   ClutterAllocationFlags allocation_flags;
647
648   /* clip, in actor coordinates */
649   cairo_rectangle_t clip;
650
651   /* the cached transformation matrix; see apply_transform() */
652   CoglMatrix transform;
653
654   guint8 opacity;
655   gint opacity_override;
656
657   ClutterOffscreenRedirect offscreen_redirect;
658
659   /* This is an internal effect used to implement the
660      offscreen-redirect property */
661   ClutterEffect *flatten_effect;
662
663   /* scene graph */
664   ClutterActor *parent;
665   ClutterActor *prev_sibling;
666   ClutterActor *next_sibling;
667   ClutterActor *first_child;
668   ClutterActor *last_child;
669
670   gint n_children;
671
672   /* tracks whenever the children of an actor are changed; the
673    * age is incremented by 1 whenever an actor is added or
674    * removed. the age is not incremented when the first or the
675    * last child pointers are changed, or when grandchildren of
676    * an actor are changed.
677    */
678   gint age;
679
680   gchar *name; /* a non-unique name, used for debugging */
681   guint32 id; /* unique id, used for backward compatibility */
682
683   gint32 pick_id; /* per-stage unique id, used for picking */
684
685   /* a back-pointer to the Pango context that we can use
686    * to create pre-configured PangoLayout
687    */
688   PangoContext *pango_context;
689
690   /* the text direction configured for this child - either by
691    * application code, or by the actor's parent
692    */
693   ClutterTextDirection text_direction;
694
695   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
696   gint internal_child;
697
698   /* meta classes */
699   ClutterMetaGroup *actions;
700   ClutterMetaGroup *constraints;
701   ClutterMetaGroup *effects;
702
703   /* delegate object used to allocate the children of this actor */
704   ClutterLayoutManager *layout_manager;
705
706   /* delegate object used to paint the contents of this actor */
707   ClutterContent *content;
708
709   ClutterActorBox content_box;
710   ClutterContentGravity content_gravity;
711   ClutterScalingFilter min_filter;
712   ClutterScalingFilter mag_filter;
713
714   /* used when painting, to update the paint volume */
715   ClutterEffect *current_effect;
716
717   /* This is used to store an effect which needs to be redrawn. A
718      redraw can be queued to start from a particular effect. This is
719      used by parametrised effects that can cache an image of the
720      actor. If a parameter of the effect changes then it only needs to
721      redraw the cached image, not the actual actor. The pointer is
722      only valid if is_dirty == TRUE. If the pointer is NULL then the
723      whole actor is dirty. */
724   ClutterEffect *effect_to_redraw;
725
726   /* This is used when painting effects to implement the
727      clutter_actor_continue_paint() function. It points to the node in
728      the list of effects that is next in the chain */
729   const GList *next_effect_to_paint;
730
731   ClutterPaintVolume paint_volume;
732
733   /* NB: This volume isn't relative to this actor, it is in eye
734    * coordinates so that it can remain valid after the actor changes.
735    */
736   ClutterPaintVolume last_paint_volume;
737
738   ClutterStageQueueRedrawEntry *queue_redraw_entry;
739
740   ClutterColor bg_color;
741
742   /* bitfields */
743
744   /* fixed position and sizes */
745   guint position_set                : 1;
746   guint min_width_set               : 1;
747   guint min_height_set              : 1;
748   guint natural_width_set           : 1;
749   guint natural_height_set          : 1;
750   /* cached request is invalid (implies allocation is too) */
751   guint needs_width_request         : 1;
752   /* cached request is invalid (implies allocation is too) */
753   guint needs_height_request        : 1;
754   /* cached allocation is invalid (request has changed, probably) */
755   guint needs_allocation            : 1;
756   guint show_on_set_parent          : 1;
757   guint has_clip                    : 1;
758   guint clip_to_allocation          : 1;
759   guint enable_model_view_transform : 1;
760   guint enable_paint_unmapped       : 1;
761   guint has_pointer                 : 1;
762   guint propagated_one_redraw       : 1;
763   guint paint_volume_valid          : 1;
764   guint last_paint_volume_valid     : 1;
765   guint in_clone_paint              : 1;
766   guint transform_valid             : 1;
767   /* This is TRUE if anything has queued a redraw since we were last
768      painted. In this case effect_to_redraw will point to an effect
769      the redraw was queued from or it will be NULL if the redraw was
770      queued without an effect. */
771   guint is_dirty                    : 1;
772   guint bg_color_set                : 1;
773   guint content_box_valid           : 1;
774   guint x_expand_set                : 1;
775   guint y_expand_set                : 1;
776   guint needs_compute_expand        : 1;
777   guint needs_x_expand              : 1;
778   guint needs_y_expand              : 1;
779 };
780
781 enum
782 {
783   PROP_0,
784
785   PROP_NAME,
786
787   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
788    * when set they force a size request, when gotten they
789    * get the allocation if the allocation is valid, and the
790    * request otherwise
791    */
792   PROP_X,
793   PROP_Y,
794   PROP_WIDTH,
795   PROP_HEIGHT,
796
797   PROP_POSITION,
798   PROP_SIZE,
799
800   /* Then the rest of these size-related properties are the "actual"
801    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
802    */
803   PROP_FIXED_X,
804   PROP_FIXED_Y,
805
806   PROP_FIXED_POSITION_SET,
807
808   PROP_MIN_WIDTH,
809   PROP_MIN_WIDTH_SET,
810
811   PROP_MIN_HEIGHT,
812   PROP_MIN_HEIGHT_SET,
813
814   PROP_NATURAL_WIDTH,
815   PROP_NATURAL_WIDTH_SET,
816
817   PROP_NATURAL_HEIGHT,
818   PROP_NATURAL_HEIGHT_SET,
819
820   PROP_REQUEST_MODE,
821
822   /* Allocation properties are read-only */
823   PROP_ALLOCATION,
824
825   PROP_DEPTH,
826
827   PROP_CLIP,
828   PROP_HAS_CLIP,
829   PROP_CLIP_TO_ALLOCATION,
830
831   PROP_OPACITY,
832
833   PROP_OFFSCREEN_REDIRECT,
834
835   PROP_VISIBLE,
836   PROP_MAPPED,
837   PROP_REALIZED,
838   PROP_REACTIVE,
839
840   PROP_SCALE_X,
841   PROP_SCALE_Y,
842   PROP_SCALE_CENTER_X,
843   PROP_SCALE_CENTER_Y,
844   PROP_SCALE_GRAVITY,
845
846   PROP_ROTATION_ANGLE_X,
847   PROP_ROTATION_ANGLE_Y,
848   PROP_ROTATION_ANGLE_Z,
849   PROP_ROTATION_CENTER_X,
850   PROP_ROTATION_CENTER_Y,
851   PROP_ROTATION_CENTER_Z,
852   /* This property only makes sense for the z rotation because the
853      others would depend on the actor having a size along the
854      z-axis */
855   PROP_ROTATION_CENTER_Z_GRAVITY,
856
857   PROP_ANCHOR_X,
858   PROP_ANCHOR_Y,
859   PROP_ANCHOR_GRAVITY,
860
861   PROP_SHOW_ON_SET_PARENT,
862
863   PROP_TEXT_DIRECTION,
864   PROP_HAS_POINTER,
865
866   PROP_ACTIONS,
867   PROP_CONSTRAINTS,
868   PROP_EFFECT,
869
870   PROP_LAYOUT_MANAGER,
871
872   PROP_X_EXPAND,
873   PROP_Y_EXPAND,
874   PROP_X_ALIGN,
875   PROP_Y_ALIGN,
876   PROP_MARGIN_TOP,
877   PROP_MARGIN_BOTTOM,
878   PROP_MARGIN_LEFT,
879   PROP_MARGIN_RIGHT,
880
881   PROP_BACKGROUND_COLOR,
882   PROP_BACKGROUND_COLOR_SET,
883
884   PROP_FIRST_CHILD,
885   PROP_LAST_CHILD,
886
887   PROP_CONTENT,
888   PROP_CONTENT_GRAVITY,
889   PROP_CONTENT_BOX,
890   PROP_MINIFICATION_FILTER,
891   PROP_MAGNIFICATION_FILTER,
892
893   PROP_LAST
894 };
895
896 static GParamSpec *obj_props[PROP_LAST];
897
898 enum
899 {
900   SHOW,
901   HIDE,
902   DESTROY,
903   PARENT_SET,
904   KEY_FOCUS_IN,
905   KEY_FOCUS_OUT,
906   PAINT,
907   PICK,
908   REALIZE,
909   UNREALIZE,
910   QUEUE_REDRAW,
911   QUEUE_RELAYOUT,
912   EVENT,
913   CAPTURED_EVENT,
914   BUTTON_PRESS_EVENT,
915   BUTTON_RELEASE_EVENT,
916   SCROLL_EVENT,
917   KEY_PRESS_EVENT,
918   KEY_RELEASE_EVENT,
919   MOTION_EVENT,
920   ENTER_EVENT,
921   LEAVE_EVENT,
922   ALLOCATION_CHANGED,
923   TRANSITIONS_COMPLETED,
924
925   LAST_SIGNAL
926 };
927
928 static guint actor_signals[LAST_SIGNAL] = { 0, };
929
930 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
931 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
932 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
933 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
934
935 /* These setters are all static for now, maybe they should be in the
936  * public API, but they are perhaps obscure enough to leave only as
937  * properties
938  */
939 static void clutter_actor_set_min_width          (ClutterActor *self,
940                                                   gfloat        min_width);
941 static void clutter_actor_set_min_height         (ClutterActor *self,
942                                                   gfloat        min_height);
943 static void clutter_actor_set_natural_width      (ClutterActor *self,
944                                                   gfloat        natural_width);
945 static void clutter_actor_set_natural_height     (ClutterActor *self,
946                                                   gfloat        natural_height);
947 static void clutter_actor_set_min_width_set      (ClutterActor *self,
948                                                   gboolean      use_min_width);
949 static void clutter_actor_set_min_height_set     (ClutterActor *self,
950                                                   gboolean      use_min_height);
951 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
952                                                   gboolean  use_natural_width);
953 static void clutter_actor_set_natural_height_set (ClutterActor *self,
954                                                   gboolean  use_natural_height);
955 static void clutter_actor_update_map_state       (ClutterActor  *self,
956                                                   MapStateChange change);
957 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
958
959 /* Helper routines for managing anchor coords */
960 static void clutter_anchor_coord_get_units (ClutterActor      *self,
961                                             const AnchorCoord *coord,
962                                             gfloat            *x,
963                                             gfloat            *y,
964                                             gfloat            *z);
965 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
966                                             gfloat             x,
967                                             gfloat             y,
968                                             gfloat             z);
969
970 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
971 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
972                                                         ClutterGravity     gravity);
973
974 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
975
976 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
977
978 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
979                                                                ClutterActor *ancestor,
980                                                                CoglMatrix *matrix);
981
982 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
983
984 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
985
986 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
987                                                                 const ClutterColor *color);
988
989 static void on_layout_manager_changed (ClutterLayoutManager *manager,
990                                        ClutterActor         *self);
991
992 static inline void clutter_actor_queue_compute_expand (ClutterActor *self);
993
994 /* Helper macro which translates by the anchor coord, applies the
995    given transformation and then translates back */
996 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
997   gfloat _tx, _ty, _tz;                                                \
998   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
999   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
1000   { _transform; }                                                      \
1001   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
1002
1003 static GQuark quark_shader_data = 0;
1004 static GQuark quark_actor_layout_info = 0;
1005 static GQuark quark_actor_transform_info = 0;
1006 static GQuark quark_actor_animation_info = 0;
1007
1008 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
1009                          clutter_actor,
1010                          G_TYPE_INITIALLY_UNOWNED,
1011                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1012                                                 clutter_container_iface_init)
1013                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1014                                                 clutter_scriptable_iface_init)
1015                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1016                                                 clutter_animatable_iface_init)
1017                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1018                                                 atk_implementor_iface_init));
1019
1020 /*< private >
1021  * clutter_actor_get_debug_name:
1022  * @actor: a #ClutterActor
1023  *
1024  * Retrieves a printable name of @actor for debugging messages
1025  *
1026  * Return value: a string with a printable name
1027  */
1028 const gchar *
1029 _clutter_actor_get_debug_name (ClutterActor *actor)
1030 {
1031   return actor->priv->name != NULL ? actor->priv->name
1032                                    : G_OBJECT_TYPE_NAME (actor);
1033 }
1034
1035 #ifdef CLUTTER_ENABLE_DEBUG
1036 /* XXX - this is for debugging only, remove once working (or leave
1037  * in only in some debug mode). Should leave it for a little while
1038  * until we're confident in the new map/realize/visible handling.
1039  */
1040 static inline void
1041 clutter_actor_verify_map_state (ClutterActor *self)
1042 {
1043   ClutterActorPrivate *priv = self->priv;
1044
1045   if (CLUTTER_ACTOR_IS_REALIZED (self))
1046     {
1047       /* all bets are off during reparent when we're potentially realized,
1048        * but should not be according to invariants
1049        */
1050       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1051         {
1052           if (priv->parent == NULL)
1053             {
1054               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1055                 {
1056                 }
1057               else
1058                 g_warning ("Realized non-toplevel actor '%s' should "
1059                            "have a parent",
1060                            _clutter_actor_get_debug_name (self));
1061             }
1062           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1063             {
1064               g_warning ("Realized actor %s has an unrealized parent %s",
1065                          _clutter_actor_get_debug_name (self),
1066                          _clutter_actor_get_debug_name (priv->parent));
1067             }
1068         }
1069     }
1070
1071   if (CLUTTER_ACTOR_IS_MAPPED (self))
1072     {
1073       if (!CLUTTER_ACTOR_IS_REALIZED (self))
1074         g_warning ("Actor '%s' is mapped but not realized",
1075                    _clutter_actor_get_debug_name (self));
1076
1077       /* remaining bets are off during reparent when we're potentially
1078        * mapped, but should not be according to invariants
1079        */
1080       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1081         {
1082           if (priv->parent == NULL)
1083             {
1084               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1085                 {
1086                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1087                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1088                     {
1089                       g_warning ("Toplevel actor '%s' is mapped "
1090                                  "but not visible",
1091                                  _clutter_actor_get_debug_name (self));
1092                     }
1093                 }
1094               else
1095                 {
1096                   g_warning ("Mapped actor '%s' should have a parent",
1097                              _clutter_actor_get_debug_name (self));
1098                 }
1099             }
1100           else
1101             {
1102               ClutterActor *iter = self;
1103
1104               /* check for the enable_paint_unmapped flag on the actor
1105                * and parents; if the flag is enabled at any point of this
1106                * branch of the scene graph then all the later checks
1107                * become pointless
1108                */
1109               while (iter != NULL)
1110                 {
1111                   if (iter->priv->enable_paint_unmapped)
1112                     return;
1113
1114                   iter = iter->priv->parent;
1115                 }
1116
1117               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1118                 {
1119                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1120                              "is not visible",
1121                              _clutter_actor_get_debug_name (self),
1122                              _clutter_actor_get_debug_name (priv->parent));
1123                 }
1124
1125               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1126                 {
1127                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1128                              "is not realized",
1129                              _clutter_actor_get_debug_name (self),
1130                              _clutter_actor_get_debug_name (priv->parent));
1131                 }
1132
1133               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1134                 {
1135                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1136                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1137                                "parent '%s' is not mapped",
1138                                _clutter_actor_get_debug_name (self),
1139                                _clutter_actor_get_debug_name (priv->parent));
1140                 }
1141             }
1142         }
1143     }
1144 }
1145
1146 #endif /* CLUTTER_ENABLE_DEBUG */
1147
1148 static void
1149 clutter_actor_set_mapped (ClutterActor *self,
1150                           gboolean      mapped)
1151 {
1152   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1153     return;
1154
1155   if (mapped)
1156     {
1157       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1158       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1159     }
1160   else
1161     {
1162       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1163       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1164     }
1165 }
1166
1167 /* this function updates the mapped and realized states according to
1168  * invariants, in the appropriate order.
1169  */
1170 static void
1171 clutter_actor_update_map_state (ClutterActor  *self,
1172                                 MapStateChange change)
1173 {
1174   gboolean was_mapped;
1175
1176   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1177
1178   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1179     {
1180       /* the mapped flag on top-level actors must be set by the
1181        * per-backend implementation because it might be asynchronous.
1182        *
1183        * That is, the MAPPED flag on toplevels currently tracks the X
1184        * server mapped-ness of the window, while the expected behavior
1185        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1186        * This creates some weird complexity by breaking the invariant
1187        * that if we're visible and all ancestors shown then we are
1188        * also mapped - instead, we are mapped if all ancestors
1189        * _possibly excepting_ the stage are mapped. The stage
1190        * will map/unmap for example when it is minimized or
1191        * moved to another workspace.
1192        *
1193        * So, the only invariant on the stage is that if visible it
1194        * should be realized, and that it has to be visible to be
1195        * mapped.
1196        */
1197       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1198         clutter_actor_realize (self);
1199
1200       switch (change)
1201         {
1202         case MAP_STATE_CHECK:
1203           break;
1204
1205         case MAP_STATE_MAKE_MAPPED:
1206           g_assert (!was_mapped);
1207           clutter_actor_set_mapped (self, TRUE);
1208           break;
1209
1210         case MAP_STATE_MAKE_UNMAPPED:
1211           g_assert (was_mapped);
1212           clutter_actor_set_mapped (self, FALSE);
1213           break;
1214
1215         case MAP_STATE_MAKE_UNREALIZED:
1216           /* we only use MAKE_UNREALIZED in unparent,
1217            * and unparenting a stage isn't possible.
1218            * If someone wants to just unrealize a stage
1219            * then clutter_actor_unrealize() doesn't
1220            * go through this codepath.
1221            */
1222           g_warning ("Trying to force unrealize stage is not allowed");
1223           break;
1224         }
1225
1226       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1227           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1228           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1229         {
1230           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1231                      "it is somehow still mapped",
1232                      _clutter_actor_get_debug_name (self));
1233         }
1234     }
1235   else
1236     {
1237       ClutterActorPrivate *priv = self->priv;
1238       ClutterActor *parent = priv->parent;
1239       gboolean should_be_mapped;
1240       gboolean may_be_realized;
1241       gboolean must_be_realized;
1242
1243       should_be_mapped = FALSE;
1244       may_be_realized = TRUE;
1245       must_be_realized = FALSE;
1246
1247       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1248         {
1249           may_be_realized = FALSE;
1250         }
1251       else
1252         {
1253           /* Maintain invariant that if parent is mapped, and we are
1254            * visible, then we are mapped ...  unless parent is a
1255            * stage, in which case we map regardless of parent's map
1256            * state but do require stage to be visible and realized.
1257            *
1258            * If parent is realized, that does not force us to be
1259            * realized; but if parent is unrealized, that does force
1260            * us to be unrealized.
1261            *
1262            * The reason we don't force children to realize with
1263            * parents is _clutter_actor_rerealize(); if we require that
1264            * a realized parent means children are realized, then to
1265            * unrealize an actor we would have to unrealize its
1266            * parents, which would end up meaning unrealizing and
1267            * hiding the entire stage. So we allow unrealizing a
1268            * child (as long as that child is not mapped) while that
1269            * child still has a realized parent.
1270            *
1271            * Also, if we unrealize from leaf nodes to root, and
1272            * realize from root to leaf, the invariants are never
1273            * violated if we allow children to be unrealized
1274            * while parents are realized.
1275            *
1276            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1277            * to force us to unmap, even though parent is still
1278            * mapped. This is because we're unmapping from leaf nodes
1279            * up to root nodes.
1280            */
1281           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1282               change != MAP_STATE_MAKE_UNMAPPED)
1283             {
1284               gboolean parent_is_visible_realized_toplevel;
1285
1286               parent_is_visible_realized_toplevel =
1287                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1288                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1289                  CLUTTER_ACTOR_IS_REALIZED (parent));
1290
1291               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1292                   parent_is_visible_realized_toplevel)
1293                 {
1294                   must_be_realized = TRUE;
1295                   should_be_mapped = TRUE;
1296                 }
1297             }
1298
1299           /* if the actor has been set to be painted even if unmapped
1300            * then we should map it and check for realization as well;
1301            * this is an override for the branch of the scene graph
1302            * which begins with this node
1303            */
1304           if (priv->enable_paint_unmapped)
1305             {
1306               if (priv->parent == NULL)
1307                 g_warning ("Attempting to map an unparented actor '%s'",
1308                            _clutter_actor_get_debug_name (self));
1309
1310               should_be_mapped = TRUE;
1311               must_be_realized = TRUE;
1312             }
1313
1314           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1315             may_be_realized = FALSE;
1316         }
1317
1318       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1319         {
1320           if (parent == NULL)
1321             g_warning ("Attempting to map a child that does not "
1322                        "meet the necessary invariants: the actor '%s' "
1323                        "has no parent",
1324                        _clutter_actor_get_debug_name (self));
1325           else
1326             g_warning ("Attempting to map a child that does not "
1327                        "meet the necessary invariants: the actor '%s' "
1328                        "is parented to an unmapped actor '%s'",
1329                        _clutter_actor_get_debug_name (self),
1330                        _clutter_actor_get_debug_name (priv->parent));
1331         }
1332
1333       /* If in reparent, we temporarily suspend unmap and unrealize.
1334        *
1335        * We want to go in the order "realize, map" and "unmap, unrealize"
1336        */
1337
1338       /* Unmap */
1339       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1340         clutter_actor_set_mapped (self, FALSE);
1341
1342       /* Realize */
1343       if (must_be_realized)
1344         clutter_actor_realize (self);
1345
1346       /* if we must be realized then we may be, presumably */
1347       g_assert (!(must_be_realized && !may_be_realized));
1348
1349       /* Unrealize */
1350       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1351         clutter_actor_unrealize_not_hiding (self);
1352
1353       /* Map */
1354       if (should_be_mapped)
1355         {
1356           if (!must_be_realized)
1357             g_warning ("Somehow we think actor '%s' should be mapped but "
1358                        "not realized, which isn't allowed",
1359                        _clutter_actor_get_debug_name (self));
1360
1361           /* realization is allowed to fail (though I don't know what
1362            * an app is supposed to do about that - shouldn't it just
1363            * be a g_error? anyway, we have to avoid mapping if this
1364            * happens)
1365            */
1366           if (CLUTTER_ACTOR_IS_REALIZED (self))
1367             clutter_actor_set_mapped (self, TRUE);
1368         }
1369     }
1370
1371 #ifdef CLUTTER_ENABLE_DEBUG
1372   /* check all invariants were kept */
1373   clutter_actor_verify_map_state (self);
1374 #endif
1375 }
1376
1377 static void
1378 clutter_actor_real_map (ClutterActor *self)
1379 {
1380   ClutterActorPrivate *priv = self->priv;
1381   ClutterActor *stage, *iter;
1382
1383   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1384
1385   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1386                 _clutter_actor_get_debug_name (self));
1387
1388   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1389
1390   stage = _clutter_actor_get_stage_internal (self);
1391   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1392
1393   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1394                 priv->pick_id,
1395                 _clutter_actor_get_debug_name (self));
1396
1397   /* notify on parent mapped before potentially mapping
1398    * children, so apps see a top-down notification.
1399    */
1400   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1401
1402   for (iter = self->priv->first_child;
1403        iter != NULL;
1404        iter = iter->priv->next_sibling)
1405     {
1406       clutter_actor_map (iter);
1407     }
1408 }
1409
1410 /**
1411  * clutter_actor_map:
1412  * @self: A #ClutterActor
1413  *
1414  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1415  * and realizes its children if they are visible. Does nothing if the
1416  * actor is not visible.
1417  *
1418  * Calling this function is strongly disencouraged: the default
1419  * implementation of #ClutterActorClass.map() will map all the children
1420  * of an actor when mapping its parent.
1421  *
1422  * When overriding map, it is mandatory to chain up to the parent
1423  * implementation.
1424  *
1425  * Since: 1.0
1426  */
1427 void
1428 clutter_actor_map (ClutterActor *self)
1429 {
1430   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1431
1432   if (CLUTTER_ACTOR_IS_MAPPED (self))
1433     return;
1434
1435   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1436     return;
1437
1438   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1439 }
1440
1441 static void
1442 clutter_actor_real_unmap (ClutterActor *self)
1443 {
1444   ClutterActorPrivate *priv = self->priv;
1445   ClutterActor *iter;
1446
1447   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1448
1449   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1450                 _clutter_actor_get_debug_name (self));
1451
1452   for (iter = self->priv->first_child;
1453        iter != NULL;
1454        iter = iter->priv->next_sibling)
1455     {
1456       clutter_actor_unmap (iter);
1457     }
1458
1459   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1460
1461   /* clear the contents of the last paint volume, so that hiding + moving +
1462    * showing will not result in the wrong area being repainted
1463    */
1464   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1465   priv->last_paint_volume_valid = TRUE;
1466
1467   /* notify on parent mapped after potentially unmapping
1468    * children, so apps see a bottom-up notification.
1469    */
1470   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1471
1472   /* relinquish keyboard focus if we were unmapped while owning it */
1473   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1474     {
1475       ClutterStage *stage;
1476
1477       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1478
1479       if (stage != NULL)
1480         _clutter_stage_release_pick_id (stage, priv->pick_id);
1481
1482       priv->pick_id = -1;
1483
1484       if (stage != NULL &&
1485           clutter_stage_get_key_focus (stage) == self)
1486         {
1487           clutter_stage_set_key_focus (stage, NULL);
1488         }
1489     }
1490 }
1491
1492 /**
1493  * clutter_actor_unmap:
1494  * @self: A #ClutterActor
1495  *
1496  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1497  * unmaps its children if they were mapped.
1498  *
1499  * Calling this function is not encouraged: the default #ClutterActor
1500  * implementation of #ClutterActorClass.unmap() will also unmap any
1501  * eventual children by default when their parent is unmapped.
1502  *
1503  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1504  * chain up to the parent implementation.
1505  *
1506  * <note>It is important to note that the implementation of the
1507  * #ClutterActorClass.unmap() virtual function may be called after
1508  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1509  * implementation, but it is guaranteed to be called before the
1510  * #GObjectClass.finalize() implementation.</note>
1511  *
1512  * Since: 1.0
1513  */
1514 void
1515 clutter_actor_unmap (ClutterActor *self)
1516 {
1517   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1518
1519   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1520     return;
1521
1522   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1523 }
1524
1525 static void
1526 clutter_actor_real_show (ClutterActor *self)
1527 {
1528   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1529     {
1530       ClutterActorPrivate *priv = self->priv;
1531
1532       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1533
1534       /* we notify on the "visible" flag in the clutter_actor_show()
1535        * wrapper so the entire show signal emission completes first
1536        * (?)
1537        */
1538       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1539
1540       /* we queue a relayout unless the actor is inside a
1541        * container that explicitly told us not to
1542        */
1543       if (priv->parent != NULL &&
1544           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1545         {
1546           /* While an actor is hidden the parent may not have
1547            * allocated/requested so we need to start from scratch
1548            * and avoid the short-circuiting in
1549            * clutter_actor_queue_relayout().
1550            */
1551           priv->needs_width_request  = FALSE;
1552           priv->needs_height_request = FALSE;
1553           priv->needs_allocation     = FALSE;
1554           clutter_actor_queue_relayout (self);
1555         }
1556     }
1557 }
1558
1559 static inline void
1560 set_show_on_set_parent (ClutterActor *self,
1561                         gboolean      set_show)
1562 {
1563   ClutterActorPrivate *priv = self->priv;
1564
1565   set_show = !!set_show;
1566
1567   if (priv->show_on_set_parent == set_show)
1568     return;
1569
1570   if (priv->parent == NULL)
1571     {
1572       priv->show_on_set_parent = set_show;
1573       g_object_notify_by_pspec (G_OBJECT (self),
1574                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1575     }
1576 }
1577
1578 /**
1579  * clutter_actor_show:
1580  * @self: A #ClutterActor
1581  *
1582  * Flags an actor to be displayed. An actor that isn't shown will not
1583  * be rendered on the stage.
1584  *
1585  * Actors are visible by default.
1586  *
1587  * If this function is called on an actor without a parent, the
1588  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1589  * effect.
1590  */
1591 void
1592 clutter_actor_show (ClutterActor *self)
1593 {
1594   ClutterActorPrivate *priv;
1595
1596   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1597
1598   /* simple optimization */
1599   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1600     {
1601       /* we still need to set the :show-on-set-parent property, in
1602        * case show() is called on an unparented actor
1603        */
1604       set_show_on_set_parent (self, TRUE);
1605       return;
1606     }
1607
1608 #ifdef CLUTTER_ENABLE_DEBUG
1609   clutter_actor_verify_map_state (self);
1610 #endif
1611
1612   priv = self->priv;
1613
1614   g_object_freeze_notify (G_OBJECT (self));
1615
1616   set_show_on_set_parent (self, TRUE);
1617
1618   /* if we're showing a child that needs to expand, or may
1619    * expand, then we need to recompute the expand flags for
1620    * its parent as well
1621    */
1622   if (priv->needs_compute_expand ||
1623       priv->needs_x_expand ||
1624       priv->needs_y_expand)
1625     {
1626       clutter_actor_queue_compute_expand (self);
1627     }
1628
1629   g_signal_emit (self, actor_signals[SHOW], 0);
1630   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1631
1632   if (priv->parent != NULL)
1633     clutter_actor_queue_redraw (priv->parent);
1634
1635   g_object_thaw_notify (G_OBJECT (self));
1636 }
1637
1638 /**
1639  * clutter_actor_show_all:
1640  * @self: a #ClutterActor
1641  *
1642  * Calls clutter_actor_show() on all children of an actor (if any).
1643  *
1644  * Since: 0.2
1645  *
1646  * Deprecated: 1.10: Actors are visible by default
1647  */
1648 void
1649 clutter_actor_show_all (ClutterActor *self)
1650 {
1651   ClutterActorClass *klass;
1652
1653   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1654
1655   klass = CLUTTER_ACTOR_GET_CLASS (self);
1656   if (klass->show_all)
1657     klass->show_all (self);
1658 }
1659
1660 static void
1661 clutter_actor_real_hide (ClutterActor *self)
1662 {
1663   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1664     {
1665       ClutterActorPrivate *priv = self->priv;
1666
1667       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1668
1669       /* we notify on the "visible" flag in the clutter_actor_hide()
1670        * wrapper so the entire hide signal emission completes first
1671        * (?)
1672        */
1673       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1674
1675       /* we queue a relayout unless the actor is inside a
1676        * container that explicitly told us not to
1677        */
1678       if (priv->parent != NULL &&
1679           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1680         clutter_actor_queue_relayout (priv->parent);
1681     }
1682 }
1683
1684 /**
1685  * clutter_actor_hide:
1686  * @self: A #ClutterActor
1687  *
1688  * Flags an actor to be hidden. A hidden actor will not be
1689  * rendered on the stage.
1690  *
1691  * Actors are visible by default.
1692  *
1693  * If this function is called on an actor without a parent, the
1694  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1695  * as a side-effect.
1696  */
1697 void
1698 clutter_actor_hide (ClutterActor *self)
1699 {
1700   ClutterActorPrivate *priv;
1701
1702   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1703
1704   /* simple optimization */
1705   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1706     {
1707       /* we still need to set the :show-on-set-parent property, in
1708        * case hide() is called on an unparented actor
1709        */
1710       set_show_on_set_parent (self, FALSE);
1711       return;
1712     }
1713
1714 #ifdef CLUTTER_ENABLE_DEBUG
1715   clutter_actor_verify_map_state (self);
1716 #endif
1717
1718   priv = self->priv;
1719
1720   g_object_freeze_notify (G_OBJECT (self));
1721
1722   set_show_on_set_parent (self, FALSE);
1723
1724   /* if we're hiding a child that needs to expand, or may
1725    * expand, then we need to recompute the expand flags for
1726    * its parent as well
1727    */
1728   if (priv->needs_compute_expand ||
1729       priv->needs_x_expand ||
1730       priv->needs_y_expand)
1731     {
1732       clutter_actor_queue_compute_expand (self);
1733     }
1734
1735   g_signal_emit (self, actor_signals[HIDE], 0);
1736   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1737
1738   if (priv->parent != NULL)
1739     clutter_actor_queue_redraw (priv->parent);
1740
1741   g_object_thaw_notify (G_OBJECT (self));
1742 }
1743
1744 /**
1745  * clutter_actor_hide_all:
1746  * @self: a #ClutterActor
1747  *
1748  * Calls clutter_actor_hide() on all child actors (if any).
1749  *
1750  * Since: 0.2
1751  *
1752  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1753  *   prevent its children from being painted as well.
1754  */
1755 void
1756 clutter_actor_hide_all (ClutterActor *self)
1757 {
1758   ClutterActorClass *klass;
1759
1760   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1761
1762   klass = CLUTTER_ACTOR_GET_CLASS (self);
1763   if (klass->hide_all)
1764     klass->hide_all (self);
1765 }
1766
1767 /**
1768  * clutter_actor_realize:
1769  * @self: A #ClutterActor
1770  *
1771  * Realization informs the actor that it is attached to a stage. It
1772  * can use this to allocate resources if it wanted to delay allocation
1773  * until it would be rendered. However it is perfectly acceptable for
1774  * an actor to create resources before being realized because Clutter
1775  * only ever has a single rendering context so that actor is free to
1776  * be moved from one stage to another.
1777  *
1778  * This function does nothing if the actor is already realized.
1779  *
1780  * Because a realized actor must have realized parent actors, calling
1781  * clutter_actor_realize() will also realize all parents of the actor.
1782  *
1783  * This function does not realize child actors, except in the special
1784  * case that realizing the stage, when the stage is visible, will
1785  * suddenly map (and thus realize) the children of the stage.
1786  **/
1787 void
1788 clutter_actor_realize (ClutterActor *self)
1789 {
1790   ClutterActorPrivate *priv;
1791
1792   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1793
1794   priv = self->priv;
1795
1796 #ifdef CLUTTER_ENABLE_DEBUG
1797   clutter_actor_verify_map_state (self);
1798 #endif
1799
1800   if (CLUTTER_ACTOR_IS_REALIZED (self))
1801     return;
1802
1803   /* To be realized, our parent actors must be realized first.
1804    * This will only succeed if we're inside a toplevel.
1805    */
1806   if (priv->parent != NULL)
1807     clutter_actor_realize (priv->parent);
1808
1809   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1810     {
1811       /* toplevels can be realized at any time */
1812     }
1813   else
1814     {
1815       /* "Fail" the realization if parent is missing or unrealized;
1816        * this should really be a g_warning() not some kind of runtime
1817        * failure; how can an app possibly recover? Instead it's a bug
1818        * in the app and the app should get an explanatory warning so
1819        * someone can fix it. But for now it's too hard to fix this
1820        * because e.g. ClutterTexture needs reworking.
1821        */
1822       if (priv->parent == NULL ||
1823           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1824         return;
1825     }
1826
1827   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1828
1829   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1830   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1831
1832   g_signal_emit (self, actor_signals[REALIZE], 0);
1833
1834   /* Stage actor is allowed to unset the realized flag again in its
1835    * default signal handler, though that is a pathological situation.
1836    */
1837
1838   /* If realization "failed" we'll have to update child state. */
1839   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1840 }
1841
1842 static void
1843 clutter_actor_real_unrealize (ClutterActor *self)
1844 {
1845   /* we must be unmapped (implying our children are also unmapped) */
1846   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1847 }
1848
1849 /**
1850  * clutter_actor_unrealize:
1851  * @self: A #ClutterActor
1852  *
1853  * Unrealization informs the actor that it may be being destroyed or
1854  * moved to another stage. The actor may want to destroy any
1855  * underlying graphics resources at this point. However it is
1856  * perfectly acceptable for it to retain the resources until the actor
1857  * is destroyed because Clutter only ever uses a single rendering
1858  * context and all of the graphics resources are valid on any stage.
1859  *
1860  * Because mapped actors must be realized, actors may not be
1861  * unrealized if they are mapped. This function hides the actor to be
1862  * sure it isn't mapped, an application-visible side effect that you
1863  * may not be expecting.
1864  *
1865  * This function should not be called by application code.
1866  */
1867 void
1868 clutter_actor_unrealize (ClutterActor *self)
1869 {
1870   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1871   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1872
1873 /* This function should not really be in the public API, because
1874  * there isn't a good reason to call it. ClutterActor will already
1875  * unrealize things for you when it's important to do so.
1876  *
1877  * If you were using clutter_actor_unrealize() in a dispose
1878  * implementation, then don't, just chain up to ClutterActor's
1879  * dispose.
1880  *
1881  * If you were using clutter_actor_unrealize() to implement
1882  * unrealizing children of your container, then don't, ClutterActor
1883  * will already take care of that.
1884  *
1885  * If you were using clutter_actor_unrealize() to re-realize to
1886  * create your resources in a different way, then use
1887  * _clutter_actor_rerealize() (inside Clutter) or just call your
1888  * code that recreates your resources directly (outside Clutter).
1889  */
1890
1891 #ifdef CLUTTER_ENABLE_DEBUG
1892   clutter_actor_verify_map_state (self);
1893 #endif
1894
1895   clutter_actor_hide (self);
1896
1897   clutter_actor_unrealize_not_hiding (self);
1898 }
1899
1900 static ClutterActorTraverseVisitFlags
1901 unrealize_actor_before_children_cb (ClutterActor *self,
1902                                     int depth,
1903                                     void *user_data)
1904 {
1905   /* If an actor is already unrealized we know its children have also
1906    * already been unrealized... */
1907   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1908     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1909
1910   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1911
1912   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1913 }
1914
1915 static ClutterActorTraverseVisitFlags
1916 unrealize_actor_after_children_cb (ClutterActor *self,
1917                                    int depth,
1918                                    void *user_data)
1919 {
1920   /* We want to unset the realized flag only _after_
1921    * child actors are unrealized, to maintain invariants.
1922    */
1923   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1924   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1925   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1926 }
1927
1928 /*
1929  * clutter_actor_unrealize_not_hiding:
1930  * @self: A #ClutterActor
1931  *
1932  * Unrealization informs the actor that it may be being destroyed or
1933  * moved to another stage. The actor may want to destroy any
1934  * underlying graphics resources at this point. However it is
1935  * perfectly acceptable for it to retain the resources until the actor
1936  * is destroyed because Clutter only ever uses a single rendering
1937  * context and all of the graphics resources are valid on any stage.
1938  *
1939  * Because mapped actors must be realized, actors may not be
1940  * unrealized if they are mapped. You must hide the actor or one of
1941  * its parents before attempting to unrealize.
1942  *
1943  * This function is separate from clutter_actor_unrealize() because it
1944  * does not automatically hide the actor.
1945  * Actors need not be hidden to be unrealized, they just need to
1946  * be unmapped. In fact we don't want to mess up the application's
1947  * setting of the "visible" flag, so hiding is very undesirable.
1948  *
1949  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1950  * backward compatibility.
1951  */
1952 static void
1953 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1954 {
1955   _clutter_actor_traverse (self,
1956                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1957                            unrealize_actor_before_children_cb,
1958                            unrealize_actor_after_children_cb,
1959                            NULL);
1960 }
1961
1962 /*
1963  * _clutter_actor_rerealize:
1964  * @self: A #ClutterActor
1965  * @callback: Function to call while unrealized
1966  * @data: data for callback
1967  *
1968  * If an actor is already unrealized, this just calls the callback.
1969  *
1970  * If it is realized, it unrealizes temporarily, calls the callback,
1971  * and then re-realizes the actor.
1972  *
1973  * As a side effect, leaves all children of the actor unrealized if
1974  * the actor was realized but not showing.  This is because when we
1975  * unrealize the actor temporarily we must unrealize its children
1976  * (e.g. children of a stage can't be realized if stage window is
1977  * gone). And we aren't clever enough to save the realization state of
1978  * all children. In most cases this should not matter, because
1979  * the children will automatically realize when they next become mapped.
1980  */
1981 void
1982 _clutter_actor_rerealize (ClutterActor    *self,
1983                           ClutterCallback  callback,
1984                           void            *data)
1985 {
1986   gboolean was_mapped;
1987   gboolean was_showing;
1988   gboolean was_realized;
1989
1990   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1991
1992 #ifdef CLUTTER_ENABLE_DEBUG
1993   clutter_actor_verify_map_state (self);
1994 #endif
1995
1996   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1997   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1998   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1999
2000   /* Must be unmapped to unrealize. Note we only have to hide this
2001    * actor if it was mapped (if all parents were showing).  If actor
2002    * is merely visible (but not mapped), then that's fine, we can
2003    * leave it visible.
2004    */
2005   if (was_mapped)
2006     clutter_actor_hide (self);
2007
2008   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
2009
2010   /* unrealize self and all children */
2011   clutter_actor_unrealize_not_hiding (self);
2012
2013   if (callback != NULL)
2014     {
2015       (* callback) (self, data);
2016     }
2017
2018   if (was_showing)
2019     clutter_actor_show (self); /* will realize only if mapping implies it */
2020   else if (was_realized)
2021     clutter_actor_realize (self); /* realize self and all parents */
2022 }
2023
2024 static void
2025 clutter_actor_real_pick (ClutterActor       *self,
2026                          const ClutterColor *color)
2027 {
2028   /* the default implementation is just to paint a rectangle
2029    * with the same size of the actor using the passed color
2030    */
2031   if (clutter_actor_should_pick_paint (self))
2032     {
2033       ClutterActorBox box = { 0, };
2034       float width, height;
2035
2036       clutter_actor_get_allocation_box (self, &box);
2037
2038       width = box.x2 - box.x1;
2039       height = box.y2 - box.y1;
2040
2041       cogl_set_source_color4ub (color->red,
2042                                 color->green,
2043                                 color->blue,
2044                                 color->alpha);
2045
2046       cogl_rectangle (0, 0, width, height);
2047     }
2048
2049   /* XXX - this thoroughly sucks, but we need to maintain compatibility
2050    * with existing container classes that override the pick() virtual
2051    * and chain up to the default implementation - otherwise we'll end up
2052    * painting our children twice.
2053    *
2054    * this has to go away for 2.0; hopefully along the pick() itself.
2055    */
2056   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2057     {
2058       ClutterActor *iter;
2059
2060       for (iter = self->priv->first_child;
2061            iter != NULL;
2062            iter = iter->priv->next_sibling)
2063         clutter_actor_paint (iter);
2064     }
2065 }
2066
2067 /**
2068  * clutter_actor_should_pick_paint:
2069  * @self: A #ClutterActor
2070  *
2071  * Should be called inside the implementation of the
2072  * #ClutterActor::pick virtual function in order to check whether
2073  * the actor should paint itself in pick mode or not.
2074  *
2075  * This function should never be called directly by applications.
2076  *
2077  * Return value: %TRUE if the actor should paint its silhouette,
2078  *   %FALSE otherwise
2079  */
2080 gboolean
2081 clutter_actor_should_pick_paint (ClutterActor *self)
2082 {
2083   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2084
2085   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2086       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2087        CLUTTER_ACTOR_IS_REACTIVE (self)))
2088     return TRUE;
2089
2090   return FALSE;
2091 }
2092
2093 static void
2094 clutter_actor_real_get_preferred_width (ClutterActor *self,
2095                                         gfloat        for_height,
2096                                         gfloat       *min_width_p,
2097                                         gfloat       *natural_width_p)
2098 {
2099   ClutterActorPrivate *priv = self->priv;
2100
2101   if (priv->n_children != 0 &&
2102       priv->layout_manager != NULL)
2103     {
2104       ClutterContainer *container = CLUTTER_CONTAINER (self);
2105
2106       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2107                     "for the preferred width",
2108                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2109                     priv->layout_manager);
2110
2111       clutter_layout_manager_get_preferred_width (priv->layout_manager,
2112                                                   container,
2113                                                   for_height,
2114                                                   min_width_p,
2115                                                   natural_width_p);
2116
2117       return;
2118     }
2119
2120   /* Default implementation is always 0x0, usually an actor
2121    * using this default is relying on someone to set the
2122    * request manually
2123    */
2124   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2125
2126   if (min_width_p)
2127     *min_width_p = 0;
2128
2129   if (natural_width_p)
2130     *natural_width_p = 0;
2131 }
2132
2133 static void
2134 clutter_actor_real_get_preferred_height (ClutterActor *self,
2135                                          gfloat        for_width,
2136                                          gfloat       *min_height_p,
2137                                          gfloat       *natural_height_p)
2138 {
2139   ClutterActorPrivate *priv = self->priv;
2140
2141   if (priv->n_children != 0 &&
2142       priv->layout_manager != NULL)
2143     {
2144       ClutterContainer *container = CLUTTER_CONTAINER (self);
2145
2146       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2147                     "for the preferred height",
2148                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2149                     priv->layout_manager);
2150
2151       clutter_layout_manager_get_preferred_height (priv->layout_manager,
2152                                                    container,
2153                                                    for_width,
2154                                                    min_height_p,
2155                                                    natural_height_p);
2156
2157       return;
2158     }
2159   /* Default implementation is always 0x0, usually an actor
2160    * using this default is relying on someone to set the
2161    * request manually
2162    */
2163   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2164
2165   if (min_height_p)
2166     *min_height_p = 0;
2167
2168   if (natural_height_p)
2169     *natural_height_p = 0;
2170 }
2171
2172 static void
2173 clutter_actor_store_old_geometry (ClutterActor    *self,
2174                                   ClutterActorBox *box)
2175 {
2176   *box = self->priv->allocation;
2177 }
2178
2179 static inline void
2180 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2181                                           const ClutterActorBox *old)
2182 {
2183   ClutterActorPrivate *priv = self->priv;
2184   GObject *obj = G_OBJECT (self);
2185
2186   g_object_freeze_notify (obj);
2187
2188   /* to avoid excessive requisition or allocation cycles we
2189    * use the cached values.
2190    *
2191    * - if we don't have an allocation we assume that we need
2192    *   to notify anyway
2193    * - if we don't have a width or a height request we notify
2194    *   width and height
2195    * - if we have a valid allocation then we check the old
2196    *   bounding box with the current allocation and we notify
2197    *   the changes
2198    */
2199   if (priv->needs_allocation)
2200     {
2201       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2202       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2203       g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2204       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2205       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2206       g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2207     }
2208   else if (priv->needs_width_request || priv->needs_height_request)
2209     {
2210       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2211       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2212       g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2213     }
2214   else
2215     {
2216       gfloat x, y;
2217       gfloat width, height;
2218
2219       x = priv->allocation.x1;
2220       y = priv->allocation.y1;
2221       width = priv->allocation.x2 - priv->allocation.x1;
2222       height = priv->allocation.y2 - priv->allocation.y1;
2223
2224       if (x != old->x1)
2225         {
2226           g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2227           g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2228         }
2229
2230       if (y != old->y1)
2231         {
2232           g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2233           g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2234         }
2235
2236       if (width != (old->x2 - old->x1))
2237         {
2238           g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2239           g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2240         }
2241
2242       if (height != (old->y2 - old->y1))
2243         {
2244           g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2245           g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2246         }
2247     }
2248
2249   g_object_thaw_notify (obj);
2250 }
2251
2252 /*< private >
2253  * clutter_actor_set_allocation_internal:
2254  * @self: a #ClutterActor
2255  * @box: a #ClutterActorBox
2256  * @flags: allocation flags
2257  *
2258  * Stores the allocation of @self.
2259  *
2260  * This function only performs basic storage and property notification.
2261  *
2262  * This function should be called by clutter_actor_set_allocation()
2263  * and by the default implementation of #ClutterActorClass.allocate().
2264  *
2265  * Return value: %TRUE if the allocation of the #ClutterActor has been
2266  *   changed, and %FALSE otherwise
2267  */
2268 static inline gboolean
2269 clutter_actor_set_allocation_internal (ClutterActor           *self,
2270                                        const ClutterActorBox  *box,
2271                                        ClutterAllocationFlags  flags)
2272 {
2273   ClutterActorPrivate *priv = self->priv;
2274   GObject *obj;
2275   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2276   gboolean retval;
2277   ClutterActorBox old_alloc = { 0, };
2278
2279   obj = G_OBJECT (self);
2280
2281   g_object_freeze_notify (obj);
2282
2283   clutter_actor_store_old_geometry (self, &old_alloc);
2284
2285   x1_changed = priv->allocation.x1 != box->x1;
2286   y1_changed = priv->allocation.y1 != box->y1;
2287   x2_changed = priv->allocation.x2 != box->x2;
2288   y2_changed = priv->allocation.y2 != box->y2;
2289
2290   priv->allocation = *box;
2291   priv->allocation_flags = flags;
2292
2293   /* allocation is authoritative */
2294   priv->needs_width_request = FALSE;
2295   priv->needs_height_request = FALSE;
2296   priv->needs_allocation = FALSE;
2297
2298   if (x1_changed ||
2299       y1_changed ||
2300       x2_changed ||
2301       y2_changed)
2302     {
2303       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2304                     _clutter_actor_get_debug_name (self));
2305
2306       priv->transform_valid = FALSE;
2307
2308       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2309
2310       /* if the allocation changes, so does the content box */
2311       if (priv->content != NULL)
2312         {
2313           priv->content_box_valid = FALSE;
2314           g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2315         }
2316
2317       retval = TRUE;
2318     }
2319   else
2320     retval = FALSE;
2321
2322   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2323
2324   g_object_thaw_notify (obj);
2325
2326   return retval;
2327 }
2328
2329 static void clutter_actor_real_allocate (ClutterActor           *self,
2330                                          const ClutterActorBox  *box,
2331                                          ClutterAllocationFlags  flags);
2332
2333 static inline void
2334 clutter_actor_maybe_layout_children (ClutterActor           *self,
2335                                      const ClutterActorBox  *allocation,
2336                                      ClutterAllocationFlags  flags)
2337 {
2338   ClutterActorPrivate *priv = self->priv;
2339
2340   /* this is going to be a bit hard to follow, so let's put an explanation
2341    * here.
2342    *
2343    * we want ClutterActor to have a default layout manager if the actor was
2344    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2345    *
2346    * we also want any subclass of ClutterActor that does not override the
2347    * ::allocate() virtual function to delegate to a layout manager.
2348    *
2349    * finally, we want to allow people subclassing ClutterActor and overriding
2350    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2351    *
2352    * on the other hand, we want existing actor subclasses overriding the
2353    * ::allocate() virtual function and chaining up to the parent's
2354    * implementation to continue working without allocating their children
2355    * twice, or without entering an allocation loop.
2356    *
2357    * for the first two points, we check if the class of the actor is
2358    * overridding the ::allocate() virtual function; if it isn't, then we
2359    * follow through with checking whether we have children and a layout
2360    * manager, and eventually calling clutter_layout_manager_allocate().
2361    *
2362    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2363    * allocation flags that we got passed, and if it is present, we continue
2364    * with the check above.
2365    *
2366    * if neither of these two checks yields a positive result, we just
2367    * assume that the ::allocate() virtual function that resulted in this
2368    * function being called will also allocate the children of the actor.
2369    */
2370
2371   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2372     goto check_layout;
2373
2374   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2375     goto check_layout;
2376
2377   return;
2378
2379 check_layout:
2380   if (priv->n_children != 0 &&
2381       priv->layout_manager != NULL)
2382     {
2383       ClutterContainer *container = CLUTTER_CONTAINER (self);
2384       ClutterAllocationFlags children_flags;
2385       ClutterActorBox children_box;
2386
2387       /* normalize the box passed to the layout manager */
2388       children_box.x1 = children_box.y1 = 0.f;
2389       children_box.x2 = (allocation->x2 - allocation->x1);
2390       children_box.y2 = (allocation->y2 - allocation->y1);
2391
2392       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2393        * the actor's children, since it refers only to the current
2394        * actor's allocation.
2395        */
2396       children_flags = flags;
2397       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2398
2399       CLUTTER_NOTE (LAYOUT,
2400                     "Allocating %d children of %s "
2401                     "at { %.2f, %.2f - %.2f x %.2f } "
2402                     "using %s",
2403                     priv->n_children,
2404                     _clutter_actor_get_debug_name (self),
2405                     allocation->x1,
2406                     allocation->y1,
2407                     (allocation->x2 - allocation->x1),
2408                     (allocation->y2 - allocation->y1),
2409                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2410
2411       clutter_layout_manager_allocate (priv->layout_manager,
2412                                        container,
2413                                        &children_box,
2414                                        children_flags);
2415     }
2416 }
2417
2418 static void
2419 clutter_actor_real_allocate (ClutterActor           *self,
2420                              const ClutterActorBox  *box,
2421                              ClutterAllocationFlags  flags)
2422 {
2423   ClutterActorPrivate *priv = self->priv;
2424   gboolean changed;
2425
2426   g_object_freeze_notify (G_OBJECT (self));
2427
2428   changed = clutter_actor_set_allocation_internal (self, box, flags);
2429
2430   /* we allocate our children before we notify changes in our geometry,
2431    * so that people connecting to properties will be able to get valid
2432    * data out of the sub-tree of the scene graph that has this actor at
2433    * the root.
2434    */
2435   clutter_actor_maybe_layout_children (self, box, flags);
2436
2437   if (changed)
2438     {
2439       ClutterActorBox signal_box = priv->allocation;
2440       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2441
2442       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2443                      &signal_box,
2444                      signal_flags);
2445     }
2446
2447   g_object_thaw_notify (G_OBJECT (self));
2448 }
2449
2450 static void
2451 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2452                                     ClutterActor *origin)
2453 {
2454   /* no point in queuing a redraw on a destroyed actor */
2455   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2456     return;
2457
2458   /* NB: We can't bail out early here if the actor is hidden in case
2459    * the actor bas been cloned. In this case the clone will need to
2460    * receive the signal so it can queue its own redraw.
2461    */
2462
2463   /* calls klass->queue_redraw in default handler */
2464   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2465 }
2466
2467 static void
2468 clutter_actor_real_queue_redraw (ClutterActor *self,
2469                                  ClutterActor *origin)
2470 {
2471   ClutterActor *parent;
2472
2473   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2474                 _clutter_actor_get_debug_name (self),
2475                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2476                                : "same actor");
2477
2478   /* no point in queuing a redraw on a destroyed actor */
2479   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2480     return;
2481
2482   /* If the queue redraw is coming from a child then the actor has
2483      become dirty and any queued effect is no longer valid */
2484   if (self != origin)
2485     {
2486       self->priv->is_dirty = TRUE;
2487       self->priv->effect_to_redraw = NULL;
2488     }
2489
2490   /* If the actor isn't visible, we still had to emit the signal
2491    * to allow for a ClutterClone, but the appearance of the parent
2492    * won't change so we don't have to propagate up the hierarchy.
2493    */
2494   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2495     return;
2496
2497   /* Although we could determine here that a full stage redraw
2498    * has already been queued and immediately bail out, we actually
2499    * guarantee that we will propagate a queue-redraw signal to our
2500    * parent at least once so that it's possible to implement a
2501    * container that tracks which of its children have queued a
2502    * redraw.
2503    */
2504   if (self->priv->propagated_one_redraw)
2505     {
2506       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2507       if (stage != NULL &&
2508           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2509         return;
2510     }
2511
2512   self->priv->propagated_one_redraw = TRUE;
2513
2514   /* notify parents, if they are all visible eventually we'll
2515    * queue redraw on the stage, which queues the redraw idle.
2516    */
2517   parent = clutter_actor_get_parent (self);
2518   if (parent != NULL)
2519     {
2520       /* this will go up recursively */
2521       _clutter_actor_signal_queue_redraw (parent, origin);
2522     }
2523 }
2524
2525 static void
2526 clutter_actor_real_queue_relayout (ClutterActor *self)
2527 {
2528   ClutterActorPrivate *priv = self->priv;
2529
2530   /* no point in queueing a redraw on a destroyed actor */
2531   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2532     return;
2533
2534   priv->needs_width_request  = TRUE;
2535   priv->needs_height_request = TRUE;
2536   priv->needs_allocation     = TRUE;
2537
2538   /* reset the cached size requests */
2539   memset (priv->width_requests, 0,
2540           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2541   memset (priv->height_requests, 0,
2542           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2543
2544   /* We need to go all the way up the hierarchy */
2545   if (priv->parent != NULL)
2546     _clutter_actor_queue_only_relayout (priv->parent);
2547 }
2548
2549 /**
2550  * clutter_actor_apply_relative_transform_to_point:
2551  * @self: A #ClutterActor
2552  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2553  *   default #ClutterStage
2554  * @point: A point as #ClutterVertex
2555  * @vertex: (out caller-allocates): The translated #ClutterVertex
2556  *
2557  * Transforms @point in coordinates relative to the actor into
2558  * ancestor-relative coordinates using the relevant transform
2559  * stack (i.e. scale, rotation, etc).
2560  *
2561  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2562  * this case, the coordinates returned will be the coordinates on
2563  * the stage before the projection is applied. This is different from
2564  * the behaviour of clutter_actor_apply_transform_to_point().
2565  *
2566  * Since: 0.6
2567  */
2568 void
2569 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2570                                                  ClutterActor        *ancestor,
2571                                                  const ClutterVertex *point,
2572                                                  ClutterVertex       *vertex)
2573 {
2574   gfloat w;
2575   CoglMatrix matrix;
2576
2577   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2578   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2579   g_return_if_fail (point != NULL);
2580   g_return_if_fail (vertex != NULL);
2581
2582   *vertex = *point;
2583   w = 1.0;
2584
2585   if (ancestor == NULL)
2586     ancestor = _clutter_actor_get_stage_internal (self);
2587
2588   if (ancestor == NULL)
2589     {
2590       *vertex = *point;
2591       return;
2592     }
2593
2594   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2595   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2596 }
2597
2598 static gboolean
2599 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2600                                          const ClutterVertex *vertices_in,
2601                                          ClutterVertex *vertices_out,
2602                                          int n_vertices)
2603 {
2604   ClutterActor *stage;
2605   CoglMatrix modelview;
2606   CoglMatrix projection;
2607   float viewport[4];
2608
2609   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2610
2611   stage = _clutter_actor_get_stage_internal (self);
2612
2613   /* We really can't do anything meaningful in this case so don't try
2614    * to do any transform */
2615   if (stage == NULL)
2616     return FALSE;
2617
2618   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2619    * that gets us to stage coordinates, we want to go all the way to eye
2620    * coordinates */
2621   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2622
2623   /* Fetch the projection and viewport */
2624   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2625   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2626                                &viewport[0],
2627                                &viewport[1],
2628                                &viewport[2],
2629                                &viewport[3]);
2630
2631   _clutter_util_fully_transform_vertices (&modelview,
2632                                           &projection,
2633                                           viewport,
2634                                           vertices_in,
2635                                           vertices_out,
2636                                           n_vertices);
2637
2638   return TRUE;
2639 }
2640
2641 /**
2642  * clutter_actor_apply_transform_to_point:
2643  * @self: A #ClutterActor
2644  * @point: A point as #ClutterVertex
2645  * @vertex: (out caller-allocates): The translated #ClutterVertex
2646  *
2647  * Transforms @point in coordinates relative to the actor
2648  * into screen-relative coordinates with the current actor
2649  * transformation (i.e. scale, rotation, etc)
2650  *
2651  * Since: 0.4
2652  **/
2653 void
2654 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2655                                         const ClutterVertex *point,
2656                                         ClutterVertex       *vertex)
2657 {
2658   g_return_if_fail (point != NULL);
2659   g_return_if_fail (vertex != NULL);
2660   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2661 }
2662
2663 /*
2664  * _clutter_actor_get_relative_transformation_matrix:
2665  * @self: The actor whose coordinate space you want to transform from.
2666  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2667  *            or %NULL if you want to transform all the way to eye coordinates.
2668  * @matrix: A #CoglMatrix to store the transformation
2669  *
2670  * This gets a transformation @matrix that will transform coordinates from the
2671  * coordinate space of @self into the coordinate space of @ancestor.
2672  *
2673  * For example if you need a matrix that can transform the local actor
2674  * coordinates of @self into stage coordinates you would pass the actor's stage
2675  * pointer as the @ancestor.
2676  *
2677  * If you pass %NULL then the transformation will take you all the way through
2678  * to eye coordinates. This can be useful if you want to extract the entire
2679  * modelview transform that Clutter applies before applying the projection
2680  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2681  * using cogl_set_modelview_matrix() for example then you would want a matrix
2682  * that transforms into eye coordinates.
2683  *
2684  * <note><para>This function explicitly initializes the given @matrix. If you just
2685  * want clutter to multiply a relative transformation with an existing matrix
2686  * you can use clutter_actor_apply_relative_transformation_matrix()
2687  * instead.</para></note>
2688  *
2689  */
2690 /* XXX: We should consider caching the stage relative modelview along with
2691  * the actor itself */
2692 static void
2693 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2694                                                    ClutterActor *ancestor,
2695                                                    CoglMatrix *matrix)
2696 {
2697   cogl_matrix_init_identity (matrix);
2698
2699   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2700 }
2701
2702 /* Project the given @box into stage window coordinates, writing the
2703  * transformed vertices to @verts[]. */
2704 static gboolean
2705 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2706                                           const ClutterActorBox *box,
2707                                           ClutterVertex          verts[])
2708 {
2709   ClutterVertex box_vertices[4];
2710
2711   box_vertices[0].x = box->x1;
2712   box_vertices[0].y = box->y1;
2713   box_vertices[0].z = 0;
2714   box_vertices[1].x = box->x2;
2715   box_vertices[1].y = box->y1;
2716   box_vertices[1].z = 0;
2717   box_vertices[2].x = box->x1;
2718   box_vertices[2].y = box->y2;
2719   box_vertices[2].z = 0;
2720   box_vertices[3].x = box->x2;
2721   box_vertices[3].y = box->y2;
2722   box_vertices[3].z = 0;
2723
2724   return
2725     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2726 }
2727
2728 /**
2729  * clutter_actor_get_allocation_vertices:
2730  * @self: A #ClutterActor
2731  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2732  *   against, or %NULL to use the #ClutterStage
2733  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2734  *   location for an array of 4 #ClutterVertex in which to store the result
2735  *
2736  * Calculates the transformed coordinates of the four corners of the
2737  * actor in the plane of @ancestor. The returned vertices relate to
2738  * the #ClutterActorBox coordinates as follows:
2739  * <itemizedlist>
2740  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2741  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2742  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2743  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2744  * </itemizedlist>
2745  *
2746  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2747  * this case, the coordinates returned will be the coordinates on
2748  * the stage before the projection is applied. This is different from
2749  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2750  *
2751  * Since: 0.6
2752  */
2753 void
2754 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2755                                        ClutterActor  *ancestor,
2756                                        ClutterVertex  verts[])
2757 {
2758   ClutterActorPrivate *priv;
2759   ClutterActorBox box;
2760   ClutterVertex vertices[4];
2761   CoglMatrix modelview;
2762
2763   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2764   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2765
2766   if (ancestor == NULL)
2767     ancestor = _clutter_actor_get_stage_internal (self);
2768
2769   /* Fallback to a NOP transform if the actor isn't parented under a
2770    * stage. */
2771   if (ancestor == NULL)
2772     ancestor = self;
2773
2774   priv = self->priv;
2775
2776   /* if the actor needs to be allocated we force a relayout, so that
2777    * we will have valid values to use in the transformations */
2778   if (priv->needs_allocation)
2779     {
2780       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2781       if (stage)
2782         _clutter_stage_maybe_relayout (stage);
2783       else
2784         {
2785           box.x1 = box.y1 = 0;
2786           /* The result isn't really meaningful in this case but at
2787            * least try to do something *vaguely* reasonable... */
2788           clutter_actor_get_size (self, &box.x2, &box.y2);
2789         }
2790     }
2791
2792   clutter_actor_get_allocation_box (self, &box);
2793
2794   vertices[0].x = box.x1;
2795   vertices[0].y = box.y1;
2796   vertices[0].z = 0;
2797   vertices[1].x = box.x2;
2798   vertices[1].y = box.y1;
2799   vertices[1].z = 0;
2800   vertices[2].x = box.x1;
2801   vertices[2].y = box.y2;
2802   vertices[2].z = 0;
2803   vertices[3].x = box.x2;
2804   vertices[3].y = box.y2;
2805   vertices[3].z = 0;
2806
2807   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2808                                                      &modelview);
2809
2810   cogl_matrix_transform_points (&modelview,
2811                                 3,
2812                                 sizeof (ClutterVertex),
2813                                 vertices,
2814                                 sizeof (ClutterVertex),
2815                                 vertices,
2816                                 4);
2817 }
2818
2819 /**
2820  * clutter_actor_get_abs_allocation_vertices:
2821  * @self: A #ClutterActor
2822  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2823  *   of 4 #ClutterVertex where to store the result.
2824  *
2825  * Calculates the transformed screen coordinates of the four corners of
2826  * the actor; the returned vertices relate to the #ClutterActorBox
2827  * coordinates  as follows:
2828  * <itemizedlist>
2829  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2830  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2831  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2832  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2833  * </itemizedlist>
2834  *
2835  * Since: 0.4
2836  */
2837 void
2838 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2839                                            ClutterVertex  verts[])
2840 {
2841   ClutterActorPrivate *priv;
2842   ClutterActorBox actor_space_allocation;
2843
2844   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2845
2846   priv = self->priv;
2847
2848   /* if the actor needs to be allocated we force a relayout, so that
2849    * the actor allocation box will be valid for
2850    * _clutter_actor_transform_and_project_box()
2851    */
2852   if (priv->needs_allocation)
2853     {
2854       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2855       /* There's nothing meaningful we can do now */
2856       if (!stage)
2857         return;
2858
2859       _clutter_stage_maybe_relayout (stage);
2860     }
2861
2862   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2863    * own coordinate space... */
2864   actor_space_allocation.x1 = 0;
2865   actor_space_allocation.y1 = 0;
2866   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2867   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2868   _clutter_actor_transform_and_project_box (self,
2869                                             &actor_space_allocation,
2870                                             verts);
2871 }
2872
2873 static void
2874 clutter_actor_real_apply_transform (ClutterActor *self,
2875                                     CoglMatrix   *matrix)
2876 {
2877   ClutterActorPrivate *priv = self->priv;
2878
2879   if (!priv->transform_valid)
2880     {
2881       CoglMatrix *transform = &priv->transform;
2882       const ClutterTransformInfo *info;
2883
2884       info = _clutter_actor_get_transform_info_or_defaults (self);
2885
2886       cogl_matrix_init_identity (transform);
2887
2888       cogl_matrix_translate (transform,
2889                              priv->allocation.x1,
2890                              priv->allocation.y1,
2891                              0.0);
2892
2893       if (info->depth)
2894         cogl_matrix_translate (transform, 0, 0, info->depth);
2895
2896       /*
2897        * because the rotation involves translations, we must scale
2898        * before applying the rotations (if we apply the scale after
2899        * the rotations, the translations included in the rotation are
2900        * not scaled and so the entire object will move on the screen
2901        * as a result of rotating it).
2902        */
2903       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2904         {
2905           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2906                                         &info->scale_center,
2907                                         cogl_matrix_scale (transform,
2908                                                            info->scale_x,
2909                                                            info->scale_y,
2910                                                            1.0));
2911         }
2912
2913       if (info->rz_angle)
2914         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2915                                       &info->rz_center,
2916                                       cogl_matrix_rotate (transform,
2917                                                           info->rz_angle,
2918                                                           0, 0, 1.0));
2919
2920       if (info->ry_angle)
2921         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2922                                       &info->ry_center,
2923                                       cogl_matrix_rotate (transform,
2924                                                           info->ry_angle,
2925                                                           0, 1.0, 0));
2926
2927       if (info->rx_angle)
2928         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2929                                       &info->rx_center,
2930                                       cogl_matrix_rotate (transform,
2931                                                           info->rx_angle,
2932                                                           1.0, 0, 0));
2933
2934       if (!clutter_anchor_coord_is_zero (&info->anchor))
2935         {
2936           gfloat x, y, z;
2937
2938           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2939           cogl_matrix_translate (transform, -x, -y, -z);
2940         }
2941
2942       priv->transform_valid = TRUE;
2943     }
2944
2945   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2946 }
2947
2948 /* Applies the transforms associated with this actor to the given
2949  * matrix. */
2950 void
2951 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2952                                           CoglMatrix *matrix)
2953 {
2954   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2955 }
2956
2957 /*
2958  * clutter_actor_apply_relative_transformation_matrix:
2959  * @self: The actor whose coordinate space you want to transform from.
2960  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2961  *            or %NULL if you want to transform all the way to eye coordinates.
2962  * @matrix: A #CoglMatrix to apply the transformation too.
2963  *
2964  * This multiplies a transform with @matrix that will transform coordinates
2965  * from the coordinate space of @self into the coordinate space of @ancestor.
2966  *
2967  * For example if you need a matrix that can transform the local actor
2968  * coordinates of @self into stage coordinates you would pass the actor's stage
2969  * pointer as the @ancestor.
2970  *
2971  * If you pass %NULL then the transformation will take you all the way through
2972  * to eye coordinates. This can be useful if you want to extract the entire
2973  * modelview transform that Clutter applies before applying the projection
2974  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2975  * using cogl_set_modelview_matrix() for example then you would want a matrix
2976  * that transforms into eye coordinates.
2977  *
2978  * <note>This function doesn't initialize the given @matrix, it simply
2979  * multiplies the requested transformation matrix with the existing contents of
2980  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2981  * before calling this function, or you can use
2982  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2983  */
2984 void
2985 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2986                                                      ClutterActor *ancestor,
2987                                                      CoglMatrix *matrix)
2988 {
2989   ClutterActor *parent;
2990
2991   /* Note we terminate before ever calling stage->apply_transform()
2992    * since that would conceptually be relative to the underlying
2993    * window OpenGL coordinates so we'd need a special @ancestor
2994    * value to represent the fake parent of the stage. */
2995   if (self == ancestor)
2996     return;
2997
2998   parent = clutter_actor_get_parent (self);
2999
3000   if (parent != NULL)
3001     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
3002                                                          matrix);
3003
3004   _clutter_actor_apply_modelview_transform (self, matrix);
3005 }
3006
3007 static void
3008 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
3009                                        ClutterPaintVolume *pv,
3010                                        const char *label,
3011                                        const CoglColor *color)
3012 {
3013   static CoglPipeline *outline = NULL;
3014   CoglPrimitive *prim;
3015   ClutterVertex line_ends[12 * 2];
3016   int n_vertices;
3017   CoglContext *ctx =
3018     clutter_backend_get_cogl_context (clutter_get_default_backend ());
3019   /* XXX: at some point we'll query this from the stage but we can't
3020    * do that until the osx backend uses Cogl natively. */
3021   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
3022
3023   if (outline == NULL)
3024     outline = cogl_pipeline_new (ctx);
3025
3026   _clutter_paint_volume_complete (pv);
3027
3028   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3029
3030   /* Front face */
3031   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3032   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3033   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3034   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3035
3036   if (!pv->is_2d)
3037     {
3038       /* Back face */
3039       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3040       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3041       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3042       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3043
3044       /* Lines connecting front face to back face */
3045       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3046       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3047       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3048       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3049     }
3050
3051   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3052                                 n_vertices,
3053                                 (CoglVertexP3 *)line_ends);
3054
3055   cogl_pipeline_set_color (outline, color);
3056   cogl_framebuffer_draw_primitive (fb, outline, prim);
3057   cogl_object_unref (prim);
3058
3059   if (label)
3060     {
3061       PangoLayout *layout;
3062       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3063       pango_layout_set_text (layout, label, -1);
3064       cogl_pango_render_layout (layout,
3065                                 pv->vertices[0].x,
3066                                 pv->vertices[0].y,
3067                                 color,
3068                                 0);
3069       g_object_unref (layout);
3070     }
3071 }
3072
3073 static void
3074 _clutter_actor_draw_paint_volume (ClutterActor *self)
3075 {
3076   ClutterPaintVolume *pv;
3077   CoglColor color;
3078
3079   pv = _clutter_actor_get_paint_volume_mutable (self);
3080   if (!pv)
3081     {
3082       gfloat width, height;
3083       ClutterPaintVolume fake_pv;
3084
3085       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3086       _clutter_paint_volume_init_static (&fake_pv, stage);
3087
3088       clutter_actor_get_size (self, &width, &height);
3089       clutter_paint_volume_set_width (&fake_pv, width);
3090       clutter_paint_volume_set_height (&fake_pv, height);
3091
3092       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3093       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3094                                              _clutter_actor_get_debug_name (self),
3095                                              &color);
3096
3097       clutter_paint_volume_free (&fake_pv);
3098     }
3099   else
3100     {
3101       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3102       _clutter_actor_draw_paint_volume_full (self, pv,
3103                                              _clutter_actor_get_debug_name (self),
3104                                              &color);
3105     }
3106 }
3107
3108 static void
3109 _clutter_actor_paint_cull_result (ClutterActor *self,
3110                                   gboolean success,
3111                                   ClutterCullResult result)
3112 {
3113   ClutterPaintVolume *pv;
3114   CoglColor color;
3115
3116   if (success)
3117     {
3118       if (result == CLUTTER_CULL_RESULT_IN)
3119         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3120       else if (result == CLUTTER_CULL_RESULT_OUT)
3121         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3122       else
3123         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3124     }
3125   else
3126     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3127
3128   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3129     _clutter_actor_draw_paint_volume_full (self, pv,
3130                                            _clutter_actor_get_debug_name (self),
3131                                            &color);
3132   else
3133     {
3134       PangoLayout *layout;
3135       char *label =
3136         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3137       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3138       cogl_set_source_color (&color);
3139
3140       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3141       pango_layout_set_text (layout, label, -1);
3142       cogl_pango_render_layout (layout,
3143                                 0,
3144                                 0,
3145                                 &color,
3146                                 0);
3147       g_free (label);
3148       g_object_unref (layout);
3149     }
3150 }
3151
3152 static int clone_paint_level = 0;
3153
3154 void
3155 _clutter_actor_push_clone_paint (void)
3156 {
3157   clone_paint_level++;
3158 }
3159
3160 void
3161 _clutter_actor_pop_clone_paint (void)
3162 {
3163   clone_paint_level--;
3164 }
3165
3166 static gboolean
3167 in_clone_paint (void)
3168 {
3169   return clone_paint_level > 0;
3170 }
3171
3172 /* Returns TRUE if the actor can be ignored */
3173 /* FIXME: we should return a ClutterCullResult, and
3174  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3175  * means there's no point in trying to cull descendants of the current
3176  * node. */
3177 static gboolean
3178 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3179 {
3180   ClutterActorPrivate *priv = self->priv;
3181   ClutterActor *stage;
3182   const ClutterPlane *stage_clip;
3183
3184   if (!priv->last_paint_volume_valid)
3185     {
3186       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3187                     "->last_paint_volume_valid == FALSE",
3188                     _clutter_actor_get_debug_name (self));
3189       return FALSE;
3190     }
3191
3192   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3193     return FALSE;
3194
3195   stage = _clutter_actor_get_stage_internal (self);
3196   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3197   if (G_UNLIKELY (!stage_clip))
3198     {
3199       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3200                     "No stage clip set",
3201                     _clutter_actor_get_debug_name (self));
3202       return FALSE;
3203     }
3204
3205   if (cogl_get_draw_framebuffer () !=
3206       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3207     {
3208       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3209                     "Current framebuffer doesn't correspond to stage",
3210                     _clutter_actor_get_debug_name (self));
3211       return FALSE;
3212     }
3213
3214   *result_out =
3215     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3216   return TRUE;
3217 }
3218
3219 static void
3220 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3221 {
3222   ClutterActorPrivate *priv = self->priv;
3223   const ClutterPaintVolume *pv;
3224
3225   if (priv->last_paint_volume_valid)
3226     {
3227       clutter_paint_volume_free (&priv->last_paint_volume);
3228       priv->last_paint_volume_valid = FALSE;
3229     }
3230
3231   pv = clutter_actor_get_paint_volume (self);
3232   if (!pv)
3233     {
3234       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3235                     "Actor failed to report a paint volume",
3236                     _clutter_actor_get_debug_name (self));
3237       return;
3238     }
3239
3240   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3241
3242   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3243                                             NULL); /* eye coordinates */
3244
3245   priv->last_paint_volume_valid = TRUE;
3246 }
3247
3248 static inline gboolean
3249 actor_has_shader_data (ClutterActor *self)
3250 {
3251   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3252 }
3253
3254 guint32
3255 _clutter_actor_get_pick_id (ClutterActor *self)
3256 {
3257   if (self->priv->pick_id < 0)
3258     return 0;
3259
3260   return self->priv->pick_id;
3261 }
3262
3263 /* This is the same as clutter_actor_add_effect except that it doesn't
3264    queue a redraw and it doesn't notify on the effect property */
3265 static void
3266 _clutter_actor_add_effect_internal (ClutterActor  *self,
3267                                     ClutterEffect *effect)
3268 {
3269   ClutterActorPrivate *priv = self->priv;
3270
3271   if (priv->effects == NULL)
3272     {
3273       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3274       priv->effects->actor = self;
3275     }
3276
3277   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3278 }
3279
3280 /* This is the same as clutter_actor_remove_effect except that it doesn't
3281    queue a redraw and it doesn't notify on the effect property */
3282 static void
3283 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3284                                        ClutterEffect *effect)
3285 {
3286   ClutterActorPrivate *priv = self->priv;
3287
3288   if (priv->effects == NULL)
3289     return;
3290
3291   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3292
3293   if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3294     g_clear_object (&priv->effects);
3295 }
3296
3297 static gboolean
3298 needs_flatten_effect (ClutterActor *self)
3299 {
3300   ClutterActorPrivate *priv = self->priv;
3301
3302   if (G_UNLIKELY (clutter_paint_debug_flags &
3303                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3304     return FALSE;
3305
3306   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3307     return TRUE;
3308   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3309     {
3310       if (clutter_actor_get_paint_opacity (self) < 255 &&
3311           clutter_actor_has_overlaps (self))
3312         return TRUE;
3313     }
3314
3315   return FALSE;
3316 }
3317
3318 static void
3319 add_or_remove_flatten_effect (ClutterActor *self)
3320 {
3321   ClutterActorPrivate *priv = self->priv;
3322
3323   /* Add or remove the flatten effect depending on the
3324      offscreen-redirect property. */
3325   if (needs_flatten_effect (self))
3326     {
3327       if (priv->flatten_effect == NULL)
3328         {
3329           ClutterActorMeta *actor_meta;
3330           gint priority;
3331
3332           priv->flatten_effect = _clutter_flatten_effect_new ();
3333           /* Keep a reference to the effect so that we can queue
3334              redraws from it */
3335           g_object_ref_sink (priv->flatten_effect);
3336
3337           /* Set the priority of the effect to high so that it will
3338              always be applied to the actor first. It uses an internal
3339              priority so that it won't be visible to applications */
3340           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3341           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3342           _clutter_actor_meta_set_priority (actor_meta, priority);
3343
3344           /* This will add the effect without queueing a redraw */
3345           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3346         }
3347     }
3348   else
3349     {
3350       if (priv->flatten_effect != NULL)
3351         {
3352           /* Destroy the effect so that it will lose its fbo cache of
3353              the actor */
3354           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3355           g_clear_object (&priv->flatten_effect);
3356         }
3357     }
3358 }
3359
3360 static void
3361 clutter_actor_real_paint (ClutterActor *actor)
3362 {
3363   ClutterActorPrivate *priv = actor->priv;
3364   ClutterActor *iter;
3365
3366   for (iter = priv->first_child;
3367        iter != NULL;
3368        iter = iter->priv->next_sibling)
3369     {
3370       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3371                     _clutter_actor_get_debug_name (iter),
3372                     _clutter_actor_get_debug_name (actor),
3373                     iter->priv->allocation.x1,
3374                     iter->priv->allocation.y1,
3375                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3376                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3377
3378       clutter_actor_paint (iter);
3379     }
3380 }
3381
3382 static gboolean
3383 clutter_actor_paint_node (ClutterActor     *actor,
3384                           ClutterPaintNode *root)
3385 {
3386   ClutterActorPrivate *priv = actor->priv;
3387
3388   if (root == NULL)
3389     return FALSE;
3390
3391   if (priv->bg_color_set &&
3392       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3393     {
3394       ClutterPaintNode *node;
3395       ClutterColor bg_color;
3396       ClutterActorBox box;
3397
3398       box.x1 = 0.f;
3399       box.y1 = 0.f;
3400       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3401       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3402
3403       bg_color = priv->bg_color;
3404       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3405                      * priv->bg_color.alpha
3406                      / 255;
3407
3408       node = clutter_color_node_new (&bg_color);
3409       clutter_paint_node_set_name (node, "backgroundColor");
3410       clutter_paint_node_add_rectangle (node, &box);
3411       clutter_paint_node_add_child (root, node);
3412       clutter_paint_node_unref (node);
3413     }
3414
3415   if (priv->content != NULL)
3416     _clutter_content_paint_content (priv->content, actor, root);
3417
3418   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3419     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3420
3421   if (clutter_paint_node_get_n_children (root) == 0)
3422     return FALSE;
3423
3424 #ifdef CLUTTER_ENABLE_DEBUG
3425   if (CLUTTER_HAS_DEBUG (PAINT))
3426     {
3427       /* dump the tree only if we have one */
3428       _clutter_paint_node_dump_tree (root);
3429     }
3430 #endif /* CLUTTER_ENABLE_DEBUG */
3431
3432   _clutter_paint_node_paint (root);
3433
3434 #if 0
3435   /* XXX: Uncomment this when we disable emitting the paint signal */
3436   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3437 #endif
3438
3439   return TRUE;
3440 }
3441
3442 /**
3443  * clutter_actor_paint:
3444  * @self: A #ClutterActor
3445  *
3446  * Renders the actor to display.
3447  *
3448  * This function should not be called directly by applications.
3449  * Call clutter_actor_queue_redraw() to queue paints, instead.
3450  *
3451  * This function is context-aware, and will either cause a
3452  * regular paint or a pick paint.
3453  *
3454  * This function will emit the #ClutterActor::paint signal or
3455  * the #ClutterActor::pick signal, depending on the context.
3456  *
3457  * This function does not paint the actor if the actor is set to 0,
3458  * unless it is performing a pick paint.
3459  */
3460 void
3461 clutter_actor_paint (ClutterActor *self)
3462 {
3463   ClutterActorPrivate *priv;
3464   ClutterPickMode pick_mode;
3465   gboolean clip_set = FALSE;
3466   gboolean shader_applied = FALSE;
3467
3468   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3469                           "Actor real-paint counter",
3470                           "Increments each time any actor is painted",
3471                           0 /* no application private data */);
3472   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3473                           "Actor pick-paint counter",
3474                           "Increments each time any actor is painted "
3475                           "for picking",
3476                           0 /* no application private data */);
3477
3478   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3479
3480   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3481     return;
3482
3483   priv = self->priv;
3484
3485   pick_mode = _clutter_context_get_pick_mode ();
3486
3487   if (pick_mode == CLUTTER_PICK_NONE)
3488     priv->propagated_one_redraw = FALSE;
3489
3490   /* It's an important optimization that we consider painting of
3491    * actors with 0 opacity to be a NOP... */
3492   if (pick_mode == CLUTTER_PICK_NONE &&
3493       /* ignore top-levels, since they might be transparent */
3494       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3495       /* Use the override opacity if its been set */
3496       ((priv->opacity_override >= 0) ?
3497        priv->opacity_override : priv->opacity) == 0)
3498     return;
3499
3500   /* if we aren't paintable (not in a toplevel with all
3501    * parents paintable) then do nothing.
3502    */
3503   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3504     return;
3505
3506   /* mark that we are in the paint process */
3507   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3508
3509   cogl_push_matrix();
3510
3511   if (priv->enable_model_view_transform)
3512     {
3513       CoglMatrix matrix;
3514
3515       /* XXX: It could be better to cache the modelview with the actor
3516        * instead of progressively building up the transformations on
3517        * the matrix stack every time we paint. */
3518       cogl_get_modelview_matrix (&matrix);
3519       _clutter_actor_apply_modelview_transform (self, &matrix);
3520
3521 #ifdef CLUTTER_ENABLE_DEBUG
3522       /* Catch when out-of-band transforms have been made by actors not as part
3523        * of an apply_transform vfunc... */
3524       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3525         {
3526           CoglMatrix expected_matrix;
3527
3528           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3529                                                              &expected_matrix);
3530
3531           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3532             {
3533               GString *buf = g_string_sized_new (1024);
3534               ClutterActor *parent;
3535
3536               parent = self;
3537               while (parent != NULL)
3538                 {
3539                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3540
3541                   if (parent->priv->parent != NULL)
3542                     g_string_append (buf, "->");
3543
3544                   parent = parent->priv->parent;
3545                 }
3546
3547               g_warning ("Unexpected transform found when painting actor "
3548                          "\"%s\". This will be caused by one of the actor's "
3549                          "ancestors (%s) using the Cogl API directly to transform "
3550                          "children instead of using ::apply_transform().",
3551                          _clutter_actor_get_debug_name (self),
3552                          buf->str);
3553
3554               g_string_free (buf, TRUE);
3555             }
3556         }
3557 #endif /* CLUTTER_ENABLE_DEBUG */
3558
3559       cogl_set_modelview_matrix (&matrix);
3560     }
3561
3562   if (priv->has_clip)
3563     {
3564       cogl_clip_push_rectangle (priv->clip.x,
3565                                 priv->clip.y,
3566                                 priv->clip.x + priv->clip.width,
3567                                 priv->clip.y + priv->clip.height);
3568       clip_set = TRUE;
3569     }
3570   else if (priv->clip_to_allocation)
3571     {
3572       gfloat width, height;
3573
3574       width  = priv->allocation.x2 - priv->allocation.x1;
3575       height = priv->allocation.y2 - priv->allocation.y1;
3576
3577       cogl_clip_push_rectangle (0, 0, width, height);
3578       clip_set = TRUE;
3579     }
3580
3581   if (pick_mode == CLUTTER_PICK_NONE)
3582     {
3583       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3584
3585       /* We check whether we need to add the flatten effect before
3586          each paint so that we can avoid having a mechanism for
3587          applications to notify when the value of the
3588          has_overlaps virtual changes. */
3589       add_or_remove_flatten_effect (self);
3590     }
3591   else
3592     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3593
3594   /* We save the current paint volume so that the next time the
3595    * actor queues a redraw we can constrain the redraw to just
3596    * cover the union of the new bounding box and the old.
3597    *
3598    * We also fetch the current paint volume to perform culling so
3599    * we can avoid painting actors outside the current clip region.
3600    *
3601    * If we are painting inside a clone, we should neither update
3602    * the paint volume or use it to cull painting, since the paint
3603    * box represents the location of the source actor on the
3604    * screen.
3605    *
3606    * XXX: We are starting to do a lot of vertex transforms on
3607    * the CPU in a typical paint, so at some point we should
3608    * audit these and consider caching some things.
3609    *
3610    * NB: We don't perform culling while picking at this point because
3611    * clutter-stage.c doesn't setup the clipping planes appropriately.
3612    *
3613    * NB: We don't want to update the last-paint-volume during picking
3614    * because the last-paint-volume is used to determine the old screen
3615    * space location of an actor that has moved so we can know the
3616    * minimal region to redraw to clear an old view of the actor. If we
3617    * update this during picking then by the time we come around to
3618    * paint then the last-paint-volume would likely represent the new
3619    * actor position not the old.
3620    */
3621   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3622     {
3623       gboolean success;
3624       /* annoyingly gcc warns if uninitialized even though
3625        * the initialization is redundant :-( */
3626       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3627
3628       if (G_LIKELY ((clutter_paint_debug_flags &
3629                      (CLUTTER_DEBUG_DISABLE_CULLING |
3630                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3631                     (CLUTTER_DEBUG_DISABLE_CULLING |
3632                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3633         _clutter_actor_update_last_paint_volume (self);
3634
3635       success = cull_actor (self, &result);
3636
3637       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3638         _clutter_actor_paint_cull_result (self, success, result);
3639       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3640         goto done;
3641     }
3642
3643   if (priv->effects == NULL)
3644     {
3645       if (pick_mode == CLUTTER_PICK_NONE &&
3646           actor_has_shader_data (self))
3647         {
3648           _clutter_actor_shader_pre_paint (self, FALSE);
3649           shader_applied = TRUE;
3650         }
3651
3652       priv->next_effect_to_paint = NULL;
3653     }
3654   else
3655     priv->next_effect_to_paint =
3656       _clutter_meta_group_peek_metas (priv->effects);
3657
3658   clutter_actor_continue_paint (self);
3659
3660   if (shader_applied)
3661     _clutter_actor_shader_post_paint (self);
3662
3663   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3664                   pick_mode == CLUTTER_PICK_NONE))
3665     _clutter_actor_draw_paint_volume (self);
3666
3667 done:
3668   /* If we make it here then the actor has run through a complete
3669      paint run including all the effects so it's no longer dirty */
3670   if (pick_mode == CLUTTER_PICK_NONE)
3671     priv->is_dirty = FALSE;
3672
3673   if (clip_set)
3674     cogl_clip_pop();
3675
3676   cogl_pop_matrix();
3677
3678   /* paint sequence complete */
3679   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3680 }
3681
3682 /**
3683  * clutter_actor_continue_paint:
3684  * @self: A #ClutterActor
3685  *
3686  * Run the next stage of the paint sequence. This function should only
3687  * be called within the implementation of the ‘run’ virtual of a
3688  * #ClutterEffect. It will cause the run method of the next effect to
3689  * be applied, or it will paint the actual actor if the current effect
3690  * is the last effect in the chain.
3691  *
3692  * Since: 1.8
3693  */
3694 void
3695 clutter_actor_continue_paint (ClutterActor *self)
3696 {
3697   ClutterActorPrivate *priv;
3698
3699   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3700   /* This should only be called from with in the ‘run’ implementation
3701      of a ClutterEffect */
3702   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3703
3704   priv = self->priv;
3705
3706   /* Skip any effects that are disabled */
3707   while (priv->next_effect_to_paint &&
3708          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3709     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3710
3711   /* If this has come from the last effect then we'll just paint the
3712      actual actor */
3713   if (priv->next_effect_to_paint == NULL)
3714     {
3715       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3716         {
3717           ClutterPaintNode *dummy;
3718
3719           /* XXX - this will go away in 2.0, when we can get rid of this
3720            * stuff and switch to a pure retained render tree of PaintNodes
3721            * for the entire frame, starting from the Stage; the paint()
3722            * virtual function can then be called directly.
3723            */
3724           dummy = _clutter_dummy_node_new (self);
3725           clutter_paint_node_set_name (dummy, "Root");
3726
3727           /* XXX - for 1.12, we use the return value of paint_node() to
3728            * decide whether we should emit the ::paint signal.
3729            */
3730           clutter_actor_paint_node (self, dummy);
3731           clutter_paint_node_unref (dummy);
3732
3733           g_signal_emit (self, actor_signals[PAINT], 0);
3734         }
3735       else
3736         {
3737           ClutterColor col = { 0, };
3738
3739           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3740
3741           /* Actor will then paint silhouette of itself in supplied
3742            * color.  See clutter_stage_get_actor_at_pos() for where
3743            * picking is enabled.
3744            */
3745           g_signal_emit (self, actor_signals[PICK], 0, &col);
3746         }
3747     }
3748   else
3749     {
3750       ClutterEffect *old_current_effect;
3751       ClutterEffectPaintFlags run_flags = 0;
3752
3753       /* Cache the current effect so that we can put it back before
3754          returning */
3755       old_current_effect = priv->current_effect;
3756
3757       priv->current_effect = priv->next_effect_to_paint->data;
3758       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3759
3760       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3761         {
3762           if (priv->is_dirty)
3763             {
3764               /* If there's an effect queued with this redraw then all
3765                  effects up to that one will be considered dirty. It
3766                  is expected the queued effect will paint the cached
3767                  image and not call clutter_actor_continue_paint again
3768                  (although it should work ok if it does) */
3769               if (priv->effect_to_redraw == NULL ||
3770                   priv->current_effect != priv->effect_to_redraw)
3771                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3772             }
3773
3774           _clutter_effect_paint (priv->current_effect, run_flags);
3775         }
3776       else
3777         {
3778           /* We can't determine when an actor has been modified since
3779              its last pick so lets just assume it has always been
3780              modified */
3781           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3782
3783           _clutter_effect_pick (priv->current_effect, run_flags);
3784         }
3785
3786       priv->current_effect = old_current_effect;
3787     }
3788 }
3789
3790 static ClutterActorTraverseVisitFlags
3791 invalidate_queue_redraw_entry (ClutterActor *self,
3792                                int           depth,
3793                                gpointer      user_data)
3794 {
3795   ClutterActorPrivate *priv = self->priv;
3796
3797   if (priv->queue_redraw_entry != NULL)
3798     {
3799       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3800       priv->queue_redraw_entry = NULL;
3801     }
3802
3803   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3804 }
3805
3806 static inline void
3807 remove_child (ClutterActor *self,
3808               ClutterActor *child)
3809 {
3810   ClutterActor *prev_sibling, *next_sibling;
3811
3812   prev_sibling = child->priv->prev_sibling;
3813   next_sibling = child->priv->next_sibling;
3814
3815   if (prev_sibling != NULL)
3816     prev_sibling->priv->next_sibling = next_sibling;
3817
3818   if (next_sibling != NULL)
3819     next_sibling->priv->prev_sibling = prev_sibling;
3820
3821   if (self->priv->first_child == child)
3822     self->priv->first_child = next_sibling;
3823
3824   if (self->priv->last_child == child)
3825     self->priv->last_child = prev_sibling;
3826
3827   child->priv->parent = NULL;
3828   child->priv->prev_sibling = NULL;
3829   child->priv->next_sibling = NULL;
3830 }
3831
3832 typedef enum {
3833   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3834   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3835   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3836   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3837   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3838   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3839
3840   /* default flags for public API */
3841   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3842                                     REMOVE_CHILD_EMIT_PARENT_SET |
3843                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3844                                     REMOVE_CHILD_CHECK_STATE |
3845                                     REMOVE_CHILD_FLUSH_QUEUE |
3846                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3847
3848   /* flags for legacy/deprecated API */
3849   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3850                                     REMOVE_CHILD_FLUSH_QUEUE |
3851                                     REMOVE_CHILD_EMIT_PARENT_SET |
3852                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3853 } ClutterActorRemoveChildFlags;
3854
3855 /*< private >
3856  * clutter_actor_remove_child_internal:
3857  * @self: a #ClutterActor
3858  * @child: the child of @self that has to be removed
3859  * @flags: control the removal operations
3860  *
3861  * Removes @child from the list of children of @self.
3862  */
3863 static void
3864 clutter_actor_remove_child_internal (ClutterActor                 *self,
3865                                      ClutterActor                 *child,
3866                                      ClutterActorRemoveChildFlags  flags)
3867 {
3868   ClutterActor *old_first, *old_last;
3869   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3870   gboolean flush_queue;
3871   gboolean notify_first_last;
3872   gboolean was_mapped;
3873
3874   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3875   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3876   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3877   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3878   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3879   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3880
3881   g_object_freeze_notify (G_OBJECT (self));
3882
3883   if (destroy_meta)
3884     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3885
3886   if (check_state)
3887     {
3888       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3889
3890       /* we need to unrealize *before* we set parent_actor to NULL,
3891        * because in an unrealize method actors are dissociating from the
3892        * stage, which means they need to be able to
3893        * clutter_actor_get_stage().
3894        *
3895        * yhis should unmap and unrealize, unless we're reparenting.
3896        */
3897       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3898     }
3899   else
3900     was_mapped = FALSE;
3901
3902   if (flush_queue)
3903     {
3904       /* We take this opportunity to invalidate any queue redraw entry
3905        * associated with the actor and descendants since we won't be able to
3906        * determine the appropriate stage after this.
3907        *
3908        * we do this after we updated the mapped state because actors might
3909        * end up queueing redraws inside their mapped/unmapped virtual
3910        * functions, and if we invalidate the redraw entry we could end up
3911        * with an inconsistent state and weird memory corruption. see
3912        * bugs:
3913        *
3914        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3915        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3916        */
3917       _clutter_actor_traverse (child,
3918                                0,
3919                                invalidate_queue_redraw_entry,
3920                                NULL,
3921                                NULL);
3922     }
3923
3924   old_first = self->priv->first_child;
3925   old_last = self->priv->last_child;
3926
3927   remove_child (self, child);
3928
3929   self->priv->n_children -= 1;
3930
3931   self->priv->age += 1;
3932
3933   /* if the child that got removed was visible and set to
3934    * expand then we want to reset the parent's state in
3935    * case the child was the only thing that was making it
3936    * expand.
3937    */
3938   if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
3939       (child->priv->needs_compute_expand ||
3940        child->priv->needs_x_expand ||
3941        child->priv->needs_y_expand))
3942     {
3943       clutter_actor_queue_compute_expand (self);
3944     }
3945
3946   /* clutter_actor_reparent() will emit ::parent-set for us */
3947   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3948     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3949
3950   /* if the child was mapped then we need to relayout ourselves to account
3951    * for the removed child
3952    */
3953   if (was_mapped)
3954     clutter_actor_queue_relayout (self);
3955
3956   /* we need to emit the signal before dropping the reference */
3957   if (emit_actor_removed)
3958     g_signal_emit_by_name (self, "actor-removed", child);
3959
3960   if (notify_first_last)
3961     {
3962       if (old_first != self->priv->first_child)
3963         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3964
3965       if (old_last != self->priv->last_child)
3966         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3967     }
3968
3969   g_object_thaw_notify (G_OBJECT (self));
3970
3971   /* remove the reference we acquired in clutter_actor_add_child() */
3972   g_object_unref (child);
3973 }
3974
3975 static const ClutterTransformInfo default_transform_info = {
3976   0.0, { 0, },          /* rotation-x */
3977   0.0, { 0, },          /* rotation-y */
3978   0.0, { 0, },          /* rotation-z */
3979
3980   1.0, 1.0, { 0, },     /* scale */
3981
3982   { 0, },               /* anchor */
3983
3984   0.0,                  /* depth */
3985 };
3986
3987 /*< private >
3988  * _clutter_actor_get_transform_info_or_defaults:
3989  * @self: a #ClutterActor
3990  *
3991  * Retrieves the ClutterTransformInfo structure associated to an actor.
3992  *
3993  * If the actor does not have a ClutterTransformInfo structure associated
3994  * to it, then the default structure will be returned.
3995  *
3996  * This function should only be used for getters.
3997  *
3998  * Return value: a const pointer to the ClutterTransformInfo structure
3999  */
4000 const ClutterTransformInfo *
4001 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
4002 {
4003   ClutterTransformInfo *info;
4004
4005   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4006   if (info != NULL)
4007     return info;
4008
4009   return &default_transform_info;
4010 }
4011
4012 static void
4013 clutter_transform_info_free (gpointer data)
4014 {
4015   if (data != NULL)
4016     g_slice_free (ClutterTransformInfo, data);
4017 }
4018
4019 /*< private >
4020  * _clutter_actor_get_transform_info:
4021  * @self: a #ClutterActor
4022  *
4023  * Retrieves a pointer to the ClutterTransformInfo structure.
4024  *
4025  * If the actor does not have a ClutterTransformInfo associated to it, one
4026  * will be created and initialized to the default values.
4027  *
4028  * This function should be used for setters.
4029  *
4030  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
4031  * instead.
4032  *
4033  * Return value: (transfer none): a pointer to the ClutterTransformInfo
4034  *   structure
4035  */
4036 ClutterTransformInfo *
4037 _clutter_actor_get_transform_info (ClutterActor *self)
4038 {
4039   ClutterTransformInfo *info;
4040
4041   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4042   if (info == NULL)
4043     {
4044       info = g_slice_new (ClutterTransformInfo);
4045
4046       *info = default_transform_info;
4047
4048       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4049                                info,
4050                                clutter_transform_info_free);
4051     }
4052
4053   return info;
4054 }
4055
4056 /*< private >
4057  * clutter_actor_set_rotation_angle_internal:
4058  * @self: a #ClutterActor
4059  * @axis: the axis of the angle to change
4060  * @angle: the angle of rotation
4061  *
4062  * Sets the rotation angle on the given axis without affecting the
4063  * rotation center point.
4064  */
4065 static inline void
4066 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
4067                                            ClutterRotateAxis  axis,
4068                                            gdouble            angle)
4069 {
4070   GObject *obj = G_OBJECT (self);
4071   ClutterTransformInfo *info;
4072
4073   info = _clutter_actor_get_transform_info (self);
4074
4075   g_object_freeze_notify (obj);
4076
4077   switch (axis)
4078     {
4079     case CLUTTER_X_AXIS:
4080       info->rx_angle = angle;
4081       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4082       break;
4083
4084     case CLUTTER_Y_AXIS:
4085       info->ry_angle = angle;
4086       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4087       break;
4088
4089     case CLUTTER_Z_AXIS:
4090       info->rz_angle = angle;
4091       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4092       break;
4093     }
4094
4095   self->priv->transform_valid = FALSE;
4096
4097   g_object_thaw_notify (obj);
4098
4099   clutter_actor_queue_redraw (self);
4100 }
4101
4102 static inline void
4103 clutter_actor_set_rotation_angle (ClutterActor      *self,
4104                                   ClutterRotateAxis  axis,
4105                                   gdouble            angle)
4106 {
4107   const ClutterTransformInfo *info;
4108   const double *cur_angle_p = NULL;
4109   GParamSpec *pspec = NULL;
4110
4111   info = _clutter_actor_get_transform_info_or_defaults (self);
4112
4113   switch (axis)
4114     {
4115     case CLUTTER_X_AXIS:
4116       cur_angle_p = &info->rx_angle;
4117       pspec = obj_props[PROP_ROTATION_ANGLE_X];
4118       break;
4119
4120     case CLUTTER_Y_AXIS:
4121       cur_angle_p = &info->ry_angle;
4122       pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4123       break;
4124
4125     case CLUTTER_Z_AXIS:
4126       cur_angle_p = &info->rz_angle;
4127       pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4128       break;
4129     }
4130
4131   g_assert (pspec != NULL);
4132   g_assert (cur_angle_p != NULL);
4133
4134   if (_clutter_actor_get_transition (self, pspec) == NULL)
4135     _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4136   else
4137     _clutter_actor_update_transition (self, pspec, angle);
4138
4139   clutter_actor_queue_redraw (self);
4140 }
4141
4142 /*< private >
4143  * clutter_actor_set_rotation_center_internal:
4144  * @self: a #ClutterActor
4145  * @axis: the axis of the center to change
4146  * @center: the coordinates of the rotation center
4147  *
4148  * Sets the rotation center on the given axis without affecting the
4149  * rotation angle.
4150  */
4151 static inline void
4152 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4153                                             ClutterRotateAxis    axis,
4154                                             const ClutterVertex *center)
4155 {
4156   GObject *obj = G_OBJECT (self);
4157   ClutterTransformInfo *info;
4158   ClutterVertex v = { 0, 0, 0 };
4159
4160   info = _clutter_actor_get_transform_info (self);
4161
4162   if (center != NULL)
4163     v = *center;
4164
4165   g_object_freeze_notify (obj);
4166
4167   switch (axis)
4168     {
4169     case CLUTTER_X_AXIS:
4170       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4171       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4172       break;
4173
4174     case CLUTTER_Y_AXIS:
4175       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4176       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4177       break;
4178
4179     case CLUTTER_Z_AXIS:
4180       /* if the previously set rotation center was fractional, then
4181        * setting explicit coordinates will have to notify the
4182        * :rotation-center-z-gravity property as well
4183        */
4184       if (info->rz_center.is_fractional)
4185         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4186
4187       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4188       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4189       break;
4190     }
4191
4192   self->priv->transform_valid = FALSE;
4193
4194   g_object_thaw_notify (obj);
4195
4196   clutter_actor_queue_redraw (self);
4197 }
4198
4199 static void
4200 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4201                                          double factor,
4202                                          GParamSpec *pspec)
4203 {
4204   GObject *obj = G_OBJECT (self);
4205   ClutterTransformInfo *info;
4206
4207   info = _clutter_actor_get_transform_info (self);
4208
4209   if (pspec == obj_props[PROP_SCALE_X])
4210     info->scale_x = factor;
4211   else
4212     info->scale_y = factor;
4213
4214   self->priv->transform_valid = FALSE;
4215   clutter_actor_queue_redraw (self);
4216   g_object_notify_by_pspec (obj, pspec);
4217 }
4218
4219 static inline void
4220 clutter_actor_set_scale_factor (ClutterActor      *self,
4221                                 ClutterRotateAxis  axis,
4222                                 gdouble            factor)
4223 {
4224   const ClutterTransformInfo *info;
4225   const double *scale_p = NULL;
4226   GParamSpec *pspec = NULL;
4227
4228   info = _clutter_actor_get_transform_info_or_defaults (self);
4229
4230   switch (axis)
4231     {
4232     case CLUTTER_X_AXIS:
4233       pspec = obj_props[PROP_SCALE_X];
4234       scale_p = &info->scale_x;
4235       break;
4236
4237     case CLUTTER_Y_AXIS:
4238       pspec = obj_props[PROP_SCALE_Y];
4239       scale_p = &info->scale_y;
4240       break;
4241
4242     case CLUTTER_Z_AXIS:
4243       break;
4244     }
4245
4246   g_assert (pspec != NULL);
4247   g_assert (scale_p != NULL);
4248
4249   if (_clutter_actor_get_transition (self, pspec) == NULL)
4250     _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4251   else
4252     _clutter_actor_update_transition (self, pspec, factor);
4253
4254   clutter_actor_queue_redraw (self);
4255 }
4256
4257 static inline void
4258 clutter_actor_set_scale_center (ClutterActor      *self,
4259                                 ClutterRotateAxis  axis,
4260                                 gfloat             coord)
4261 {
4262   GObject *obj = G_OBJECT (self);
4263   ClutterTransformInfo *info;
4264   gfloat center_x, center_y;
4265
4266   info = _clutter_actor_get_transform_info (self);
4267
4268   g_object_freeze_notify (obj);
4269
4270   /* get the current scale center coordinates */
4271   clutter_anchor_coord_get_units (self, &info->scale_center,
4272                                   &center_x,
4273                                   &center_y,
4274                                   NULL);
4275
4276   /* we need to notify this too, because setting explicit coordinates will
4277    * change the gravity as a side effect
4278    */
4279   if (info->scale_center.is_fractional)
4280     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4281
4282   switch (axis)
4283     {
4284     case CLUTTER_X_AXIS:
4285       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4286       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4287       break;
4288
4289     case CLUTTER_Y_AXIS:
4290       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4291       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4292       break;
4293
4294     default:
4295       g_assert_not_reached ();
4296     }
4297
4298   self->priv->transform_valid = FALSE;
4299
4300   clutter_actor_queue_redraw (self);
4301
4302   g_object_thaw_notify (obj);
4303 }
4304
4305 static inline void
4306 clutter_actor_set_scale_gravity (ClutterActor   *self,
4307                                  ClutterGravity  gravity)
4308 {
4309   ClutterTransformInfo *info;
4310   GObject *obj;
4311
4312   info = _clutter_actor_get_transform_info (self);
4313   obj = G_OBJECT (self);
4314
4315   if (gravity == CLUTTER_GRAVITY_NONE)
4316     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4317   else
4318     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4319
4320   self->priv->transform_valid = FALSE;
4321
4322   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4323   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4324   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4325
4326   clutter_actor_queue_redraw (self);
4327 }
4328
4329 static inline void
4330 clutter_actor_set_anchor_coord (ClutterActor      *self,
4331                                 ClutterRotateAxis  axis,
4332                                 gfloat             coord)
4333 {
4334   GObject *obj = G_OBJECT (self);
4335   ClutterTransformInfo *info;
4336   gfloat anchor_x, anchor_y;
4337
4338   info = _clutter_actor_get_transform_info (self);
4339
4340   g_object_freeze_notify (obj);
4341
4342   clutter_anchor_coord_get_units (self, &info->anchor,
4343                                   &anchor_x,
4344                                   &anchor_y,
4345                                   NULL);
4346
4347   if (info->anchor.is_fractional)
4348     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4349
4350   switch (axis)
4351     {
4352     case CLUTTER_X_AXIS:
4353       clutter_anchor_coord_set_units (&info->anchor,
4354                                       coord,
4355                                       anchor_y,
4356                                       0.0);
4357       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4358       break;
4359
4360     case CLUTTER_Y_AXIS:
4361       clutter_anchor_coord_set_units (&info->anchor,
4362                                       anchor_x,
4363                                       coord,
4364                                       0.0);
4365       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4366       break;
4367
4368     default:
4369       g_assert_not_reached ();
4370     }
4371
4372   self->priv->transform_valid = FALSE;
4373
4374   clutter_actor_queue_redraw (self);
4375
4376   g_object_thaw_notify (obj);
4377 }
4378
4379 static void
4380 clutter_actor_set_property (GObject      *object,
4381                             guint         prop_id,
4382                             const GValue *value,
4383                             GParamSpec   *pspec)
4384 {
4385   ClutterActor *actor = CLUTTER_ACTOR (object);
4386   ClutterActorPrivate *priv = actor->priv;
4387
4388   switch (prop_id)
4389     {
4390     case PROP_X:
4391       clutter_actor_set_x (actor, g_value_get_float (value));
4392       break;
4393
4394     case PROP_Y:
4395       clutter_actor_set_y (actor, g_value_get_float (value));
4396       break;
4397
4398     case PROP_POSITION:
4399       {
4400         const ClutterPoint *pos = g_value_get_boxed (value);
4401
4402         if (pos != NULL)
4403           clutter_actor_set_position (actor, pos->x, pos->y);
4404         else
4405           clutter_actor_set_fixed_position_set (actor, FALSE);
4406       }
4407       break;
4408
4409     case PROP_WIDTH:
4410       clutter_actor_set_width (actor, g_value_get_float (value));
4411       break;
4412
4413     case PROP_HEIGHT:
4414       clutter_actor_set_height (actor, g_value_get_float (value));
4415       break;
4416
4417     case PROP_SIZE:
4418       {
4419         const ClutterSize *size = g_value_get_boxed (value);
4420
4421         if (size != NULL)
4422           clutter_actor_set_size (actor, size->width, size->height);
4423         else
4424           clutter_actor_set_size (actor, -1, -1);
4425       }
4426       break;
4427
4428     case PROP_FIXED_X:
4429       clutter_actor_set_x (actor, g_value_get_float (value));
4430       break;
4431
4432     case PROP_FIXED_Y:
4433       clutter_actor_set_y (actor, g_value_get_float (value));
4434       break;
4435
4436     case PROP_FIXED_POSITION_SET:
4437       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4438       break;
4439
4440     case PROP_MIN_WIDTH:
4441       clutter_actor_set_min_width (actor, g_value_get_float (value));
4442       break;
4443
4444     case PROP_MIN_HEIGHT:
4445       clutter_actor_set_min_height (actor, g_value_get_float (value));
4446       break;
4447
4448     case PROP_NATURAL_WIDTH:
4449       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4450       break;
4451
4452     case PROP_NATURAL_HEIGHT:
4453       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4454       break;
4455
4456     case PROP_MIN_WIDTH_SET:
4457       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4458       break;
4459
4460     case PROP_MIN_HEIGHT_SET:
4461       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4462       break;
4463
4464     case PROP_NATURAL_WIDTH_SET:
4465       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4466       break;
4467
4468     case PROP_NATURAL_HEIGHT_SET:
4469       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4470       break;
4471
4472     case PROP_REQUEST_MODE:
4473       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4474       break;
4475
4476     case PROP_DEPTH:
4477       clutter_actor_set_depth (actor, g_value_get_float (value));
4478       break;
4479
4480     case PROP_OPACITY:
4481       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4482       break;
4483
4484     case PROP_OFFSCREEN_REDIRECT:
4485       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4486       break;
4487
4488     case PROP_NAME:
4489       clutter_actor_set_name (actor, g_value_get_string (value));
4490       break;
4491
4492     case PROP_VISIBLE:
4493       if (g_value_get_boolean (value) == TRUE)
4494         clutter_actor_show (actor);
4495       else
4496         clutter_actor_hide (actor);
4497       break;
4498
4499     case PROP_SCALE_X:
4500       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4501                                       g_value_get_double (value));
4502       break;
4503
4504     case PROP_SCALE_Y:
4505       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4506                                       g_value_get_double (value));
4507       break;
4508
4509     case PROP_SCALE_CENTER_X:
4510       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4511                                       g_value_get_float (value));
4512       break;
4513
4514     case PROP_SCALE_CENTER_Y:
4515       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4516                                       g_value_get_float (value));
4517       break;
4518
4519     case PROP_SCALE_GRAVITY:
4520       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4521       break;
4522
4523     case PROP_CLIP:
4524       {
4525         const ClutterGeometry *geom = g_value_get_boxed (value);
4526
4527         clutter_actor_set_clip (actor,
4528                                 geom->x, geom->y,
4529                                 geom->width, geom->height);
4530       }
4531       break;
4532
4533     case PROP_CLIP_TO_ALLOCATION:
4534       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4535       break;
4536
4537     case PROP_REACTIVE:
4538       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4539       break;
4540
4541     case PROP_ROTATION_ANGLE_X:
4542       clutter_actor_set_rotation_angle (actor,
4543                                         CLUTTER_X_AXIS,
4544                                         g_value_get_double (value));
4545       break;
4546
4547     case PROP_ROTATION_ANGLE_Y:
4548       clutter_actor_set_rotation_angle (actor,
4549                                         CLUTTER_Y_AXIS,
4550                                         g_value_get_double (value));
4551       break;
4552
4553     case PROP_ROTATION_ANGLE_Z:
4554       clutter_actor_set_rotation_angle (actor,
4555                                         CLUTTER_Z_AXIS,
4556                                         g_value_get_double (value));
4557       break;
4558
4559     case PROP_ROTATION_CENTER_X:
4560       clutter_actor_set_rotation_center_internal (actor,
4561                                                   CLUTTER_X_AXIS,
4562                                                   g_value_get_boxed (value));
4563       break;
4564
4565     case PROP_ROTATION_CENTER_Y:
4566       clutter_actor_set_rotation_center_internal (actor,
4567                                                   CLUTTER_Y_AXIS,
4568                                                   g_value_get_boxed (value));
4569       break;
4570
4571     case PROP_ROTATION_CENTER_Z:
4572       clutter_actor_set_rotation_center_internal (actor,
4573                                                   CLUTTER_Z_AXIS,
4574                                                   g_value_get_boxed (value));
4575       break;
4576
4577     case PROP_ROTATION_CENTER_Z_GRAVITY:
4578       {
4579         const ClutterTransformInfo *info;
4580
4581         info = _clutter_actor_get_transform_info_or_defaults (actor);
4582         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4583                                                    g_value_get_enum (value));
4584       }
4585       break;
4586
4587     case PROP_ANCHOR_X:
4588       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4589                                       g_value_get_float (value));
4590       break;
4591
4592     case PROP_ANCHOR_Y:
4593       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4594                                       g_value_get_float (value));
4595       break;
4596
4597     case PROP_ANCHOR_GRAVITY:
4598       clutter_actor_set_anchor_point_from_gravity (actor,
4599                                                    g_value_get_enum (value));
4600       break;
4601
4602     case PROP_SHOW_ON_SET_PARENT:
4603       priv->show_on_set_parent = g_value_get_boolean (value);
4604       break;
4605
4606     case PROP_TEXT_DIRECTION:
4607       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4608       break;
4609
4610     case PROP_ACTIONS:
4611       clutter_actor_add_action (actor, g_value_get_object (value));
4612       break;
4613
4614     case PROP_CONSTRAINTS:
4615       clutter_actor_add_constraint (actor, g_value_get_object (value));
4616       break;
4617
4618     case PROP_EFFECT:
4619       clutter_actor_add_effect (actor, g_value_get_object (value));
4620       break;
4621
4622     case PROP_LAYOUT_MANAGER:
4623       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4624       break;
4625
4626     case PROP_X_EXPAND:
4627       clutter_actor_set_x_expand (actor, g_value_get_boolean (value));
4628       break;
4629
4630     case PROP_Y_EXPAND:
4631       clutter_actor_set_y_expand (actor, g_value_get_boolean (value));
4632       break;
4633
4634     case PROP_X_ALIGN:
4635       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4636       break;
4637
4638     case PROP_Y_ALIGN:
4639       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4640       break;
4641
4642     case PROP_MARGIN_TOP:
4643       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4644       break;
4645
4646     case PROP_MARGIN_BOTTOM:
4647       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4648       break;
4649
4650     case PROP_MARGIN_LEFT:
4651       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4652       break;
4653
4654     case PROP_MARGIN_RIGHT:
4655       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4656       break;
4657
4658     case PROP_BACKGROUND_COLOR:
4659       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4660       break;
4661
4662     case PROP_CONTENT:
4663       clutter_actor_set_content (actor, g_value_get_object (value));
4664       break;
4665
4666     case PROP_CONTENT_GRAVITY:
4667       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4668       break;
4669
4670     case PROP_MINIFICATION_FILTER:
4671       clutter_actor_set_content_scaling_filters (actor,
4672                                                  g_value_get_enum (value),
4673                                                  actor->priv->mag_filter);
4674       break;
4675
4676     case PROP_MAGNIFICATION_FILTER:
4677       clutter_actor_set_content_scaling_filters (actor,
4678                                                  actor->priv->min_filter,
4679                                                  g_value_get_enum (value));
4680       break;
4681
4682     default:
4683       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4684       break;
4685     }
4686 }
4687
4688 static void
4689 clutter_actor_get_property (GObject    *object,
4690                             guint       prop_id,
4691                             GValue     *value,
4692                             GParamSpec *pspec)
4693 {
4694   ClutterActor *actor = CLUTTER_ACTOR (object);
4695   ClutterActorPrivate *priv = actor->priv;
4696
4697   switch (prop_id)
4698     {
4699     case PROP_X:
4700       g_value_set_float (value, clutter_actor_get_x (actor));
4701       break;
4702
4703     case PROP_Y:
4704       g_value_set_float (value, clutter_actor_get_y (actor));
4705       break;
4706
4707     case PROP_POSITION:
4708       {
4709         ClutterPoint position;
4710
4711         clutter_point_init (&position,
4712                             clutter_actor_get_x (actor),
4713                             clutter_actor_get_y (actor));
4714         g_value_set_boxed (value, &position);
4715       }
4716       break;
4717
4718     case PROP_WIDTH:
4719       g_value_set_float (value, clutter_actor_get_width (actor));
4720       break;
4721
4722     case PROP_HEIGHT:
4723       g_value_set_float (value, clutter_actor_get_height (actor));
4724       break;
4725
4726     case PROP_SIZE:
4727       {
4728         ClutterSize size;
4729
4730         clutter_size_init (&size,
4731                            clutter_actor_get_width (actor),
4732                            clutter_actor_get_height (actor));
4733         g_value_set_boxed (value, &size);
4734       }
4735       break;
4736
4737     case PROP_FIXED_X:
4738       {
4739         const ClutterLayoutInfo *info;
4740
4741         info = _clutter_actor_get_layout_info_or_defaults (actor);
4742         g_value_set_float (value, info->fixed_pos.x);
4743       }
4744       break;
4745
4746     case PROP_FIXED_Y:
4747       {
4748         const ClutterLayoutInfo *info;
4749
4750         info = _clutter_actor_get_layout_info_or_defaults (actor);
4751         g_value_set_float (value, info->fixed_pos.y);
4752       }
4753       break;
4754
4755     case PROP_FIXED_POSITION_SET:
4756       g_value_set_boolean (value, priv->position_set);
4757       break;
4758
4759     case PROP_MIN_WIDTH:
4760       {
4761         const ClutterLayoutInfo *info;
4762
4763         info = _clutter_actor_get_layout_info_or_defaults (actor);
4764         g_value_set_float (value, info->minimum.width);
4765       }
4766       break;
4767
4768     case PROP_MIN_HEIGHT:
4769       {
4770         const ClutterLayoutInfo *info;
4771
4772         info = _clutter_actor_get_layout_info_or_defaults (actor);
4773         g_value_set_float (value, info->minimum.height);
4774       }
4775       break;
4776
4777     case PROP_NATURAL_WIDTH:
4778       {
4779         const ClutterLayoutInfo *info;
4780
4781         info = _clutter_actor_get_layout_info_or_defaults (actor);
4782         g_value_set_float (value, info->natural.width);
4783       }
4784       break;
4785
4786     case PROP_NATURAL_HEIGHT:
4787       {
4788         const ClutterLayoutInfo *info;
4789
4790         info = _clutter_actor_get_layout_info_or_defaults (actor);
4791         g_value_set_float (value, info->natural.height);
4792       }
4793       break;
4794
4795     case PROP_MIN_WIDTH_SET:
4796       g_value_set_boolean (value, priv->min_width_set);
4797       break;
4798
4799     case PROP_MIN_HEIGHT_SET:
4800       g_value_set_boolean (value, priv->min_height_set);
4801       break;
4802
4803     case PROP_NATURAL_WIDTH_SET:
4804       g_value_set_boolean (value, priv->natural_width_set);
4805       break;
4806
4807     case PROP_NATURAL_HEIGHT_SET:
4808       g_value_set_boolean (value, priv->natural_height_set);
4809       break;
4810
4811     case PROP_REQUEST_MODE:
4812       g_value_set_enum (value, priv->request_mode);
4813       break;
4814
4815     case PROP_ALLOCATION:
4816       g_value_set_boxed (value, &priv->allocation);
4817       break;
4818
4819     case PROP_DEPTH:
4820       g_value_set_float (value, clutter_actor_get_depth (actor));
4821       break;
4822
4823     case PROP_OPACITY:
4824       g_value_set_uint (value, priv->opacity);
4825       break;
4826
4827     case PROP_OFFSCREEN_REDIRECT:
4828       g_value_set_enum (value, priv->offscreen_redirect);
4829       break;
4830
4831     case PROP_NAME:
4832       g_value_set_string (value, priv->name);
4833       break;
4834
4835     case PROP_VISIBLE:
4836       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4837       break;
4838
4839     case PROP_MAPPED:
4840       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4841       break;
4842
4843     case PROP_REALIZED:
4844       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4845       break;
4846
4847     case PROP_HAS_CLIP:
4848       g_value_set_boolean (value, priv->has_clip);
4849       break;
4850
4851     case PROP_CLIP:
4852       {
4853         ClutterGeometry clip;
4854
4855         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4856         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4857         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4858         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4859
4860         g_value_set_boxed (value, &clip);
4861       }
4862       break;
4863
4864     case PROP_CLIP_TO_ALLOCATION:
4865       g_value_set_boolean (value, priv->clip_to_allocation);
4866       break;
4867
4868     case PROP_SCALE_X:
4869       {
4870         const ClutterTransformInfo *info;
4871
4872         info = _clutter_actor_get_transform_info_or_defaults (actor);
4873         g_value_set_double (value, info->scale_x);
4874       }
4875       break;
4876
4877     case PROP_SCALE_Y:
4878       {
4879         const ClutterTransformInfo *info;
4880
4881         info = _clutter_actor_get_transform_info_or_defaults (actor);
4882         g_value_set_double (value, info->scale_y);
4883       }
4884       break;
4885
4886     case PROP_SCALE_CENTER_X:
4887       {
4888         gfloat center;
4889
4890         clutter_actor_get_scale_center (actor, &center, NULL);
4891
4892         g_value_set_float (value, center);
4893       }
4894       break;
4895
4896     case PROP_SCALE_CENTER_Y:
4897       {
4898         gfloat center;
4899
4900         clutter_actor_get_scale_center (actor, NULL, &center);
4901
4902         g_value_set_float (value, center);
4903       }
4904       break;
4905
4906     case PROP_SCALE_GRAVITY:
4907       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4908       break;
4909
4910     case PROP_REACTIVE:
4911       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4912       break;
4913
4914     case PROP_ROTATION_ANGLE_X:
4915       {
4916         const ClutterTransformInfo *info;
4917
4918         info = _clutter_actor_get_transform_info_or_defaults (actor);
4919         g_value_set_double (value, info->rx_angle);
4920       }
4921       break;
4922
4923     case PROP_ROTATION_ANGLE_Y:
4924       {
4925         const ClutterTransformInfo *info;
4926
4927         info = _clutter_actor_get_transform_info_or_defaults (actor);
4928         g_value_set_double (value, info->ry_angle);
4929       }
4930       break;
4931
4932     case PROP_ROTATION_ANGLE_Z:
4933       {
4934         const ClutterTransformInfo *info;
4935
4936         info = _clutter_actor_get_transform_info_or_defaults (actor);
4937         g_value_set_double (value, info->rz_angle);
4938       }
4939       break;
4940
4941     case PROP_ROTATION_CENTER_X:
4942       {
4943         ClutterVertex center;
4944
4945         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4946                                     &center.x,
4947                                     &center.y,
4948                                     &center.z);
4949
4950         g_value_set_boxed (value, &center);
4951       }
4952       break;
4953
4954     case PROP_ROTATION_CENTER_Y:
4955       {
4956         ClutterVertex center;
4957
4958         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4959                                     &center.x,
4960                                     &center.y,
4961                                     &center.z);
4962
4963         g_value_set_boxed (value, &center);
4964       }
4965       break;
4966
4967     case PROP_ROTATION_CENTER_Z:
4968       {
4969         ClutterVertex center;
4970
4971         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4972                                     &center.x,
4973                                     &center.y,
4974                                     &center.z);
4975
4976         g_value_set_boxed (value, &center);
4977       }
4978       break;
4979
4980     case PROP_ROTATION_CENTER_Z_GRAVITY:
4981       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4982       break;
4983
4984     case PROP_ANCHOR_X:
4985       {
4986         const ClutterTransformInfo *info;
4987         gfloat anchor_x;
4988
4989         info = _clutter_actor_get_transform_info_or_defaults (actor);
4990         clutter_anchor_coord_get_units (actor, &info->anchor,
4991                                         &anchor_x,
4992                                         NULL,
4993                                         NULL);
4994         g_value_set_float (value, anchor_x);
4995       }
4996       break;
4997
4998     case PROP_ANCHOR_Y:
4999       {
5000         const ClutterTransformInfo *info;
5001         gfloat anchor_y;
5002
5003         info = _clutter_actor_get_transform_info_or_defaults (actor);
5004         clutter_anchor_coord_get_units (actor, &info->anchor,
5005                                         NULL,
5006                                         &anchor_y,
5007                                         NULL);
5008         g_value_set_float (value, anchor_y);
5009       }
5010       break;
5011
5012     case PROP_ANCHOR_GRAVITY:
5013       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
5014       break;
5015
5016     case PROP_SHOW_ON_SET_PARENT:
5017       g_value_set_boolean (value, priv->show_on_set_parent);
5018       break;
5019
5020     case PROP_TEXT_DIRECTION:
5021       g_value_set_enum (value, priv->text_direction);
5022       break;
5023
5024     case PROP_HAS_POINTER:
5025       g_value_set_boolean (value, priv->has_pointer);
5026       break;
5027
5028     case PROP_LAYOUT_MANAGER:
5029       g_value_set_object (value, priv->layout_manager);
5030       break;
5031
5032     case PROP_X_EXPAND:
5033       {
5034         const ClutterLayoutInfo *info;
5035
5036         info = _clutter_actor_get_layout_info_or_defaults (actor);
5037         g_value_set_boolean (value, info->x_expand);
5038       }
5039       break;
5040
5041     case PROP_Y_EXPAND:
5042       {
5043         const ClutterLayoutInfo *info;
5044
5045         info = _clutter_actor_get_layout_info_or_defaults (actor);
5046         g_value_set_boolean (value, info->y_expand);
5047       }
5048       break;
5049
5050     case PROP_X_ALIGN:
5051       {
5052         const ClutterLayoutInfo *info;
5053
5054         info = _clutter_actor_get_layout_info_or_defaults (actor);
5055         g_value_set_enum (value, info->x_align);
5056       }
5057       break;
5058
5059     case PROP_Y_ALIGN:
5060       {
5061         const ClutterLayoutInfo *info;
5062
5063         info = _clutter_actor_get_layout_info_or_defaults (actor);
5064         g_value_set_enum (value, info->y_align);
5065       }
5066       break;
5067
5068     case PROP_MARGIN_TOP:
5069       {
5070         const ClutterLayoutInfo *info;
5071
5072         info = _clutter_actor_get_layout_info_or_defaults (actor);
5073         g_value_set_float (value, info->margin.top);
5074       }
5075       break;
5076
5077     case PROP_MARGIN_BOTTOM:
5078       {
5079         const ClutterLayoutInfo *info;
5080
5081         info = _clutter_actor_get_layout_info_or_defaults (actor);
5082         g_value_set_float (value, info->margin.bottom);
5083       }
5084       break;
5085
5086     case PROP_MARGIN_LEFT:
5087       {
5088         const ClutterLayoutInfo *info;
5089
5090         info = _clutter_actor_get_layout_info_or_defaults (actor);
5091         g_value_set_float (value, info->margin.left);
5092       }
5093       break;
5094
5095     case PROP_MARGIN_RIGHT:
5096       {
5097         const ClutterLayoutInfo *info;
5098
5099         info = _clutter_actor_get_layout_info_or_defaults (actor);
5100         g_value_set_float (value, info->margin.right);
5101       }
5102       break;
5103
5104     case PROP_BACKGROUND_COLOR_SET:
5105       g_value_set_boolean (value, priv->bg_color_set);
5106       break;
5107
5108     case PROP_BACKGROUND_COLOR:
5109       g_value_set_boxed (value, &priv->bg_color);
5110       break;
5111
5112     case PROP_FIRST_CHILD:
5113       g_value_set_object (value, priv->first_child);
5114       break;
5115
5116     case PROP_LAST_CHILD:
5117       g_value_set_object (value, priv->last_child);
5118       break;
5119
5120     case PROP_CONTENT:
5121       g_value_set_object (value, priv->content);
5122       break;
5123
5124     case PROP_CONTENT_GRAVITY:
5125       g_value_set_enum (value, priv->content_gravity);
5126       break;
5127
5128     case PROP_CONTENT_BOX:
5129       {
5130         ClutterActorBox box = { 0, };
5131
5132         clutter_actor_get_content_box (actor, &box);
5133         g_value_set_boxed (value, &box);
5134       }
5135       break;
5136
5137     case PROP_MINIFICATION_FILTER:
5138       g_value_set_enum (value, priv->min_filter);
5139       break;
5140
5141     case PROP_MAGNIFICATION_FILTER:
5142       g_value_set_enum (value, priv->mag_filter);
5143       break;
5144
5145     default:
5146       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5147       break;
5148     }
5149 }
5150
5151 static void
5152 clutter_actor_dispose (GObject *object)
5153 {
5154   ClutterActor *self = CLUTTER_ACTOR (object);
5155   ClutterActorPrivate *priv = self->priv;
5156
5157   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5158                 priv->id,
5159                 g_type_name (G_OBJECT_TYPE (self)),
5160                 object->ref_count);
5161
5162   g_signal_emit (self, actor_signals[DESTROY], 0);
5163
5164   /* avoid recursing when called from clutter_actor_destroy() */
5165   if (priv->parent != NULL)
5166     {
5167       ClutterActor *parent = priv->parent;
5168
5169       /* go through the Container implementation unless this
5170        * is an internal child and has been marked as such.
5171        *
5172        * removing the actor from its parent will reset the
5173        * realized and mapped states.
5174        */
5175       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5176         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5177       else
5178         clutter_actor_remove_child_internal (parent, self,
5179                                              REMOVE_CHILD_LEGACY_FLAGS);
5180     }
5181
5182   /* parent must be gone at this point */
5183   g_assert (priv->parent == NULL);
5184
5185   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5186     {
5187       /* can't be mapped or realized with no parent */
5188       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5189       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5190     }
5191
5192   g_clear_object (&priv->pango_context);
5193   g_clear_object (&priv->actions);
5194   g_clear_object (&priv->constraints);
5195   g_clear_object (&priv->effects);
5196   g_clear_object (&priv->flatten_effect);
5197
5198   if (priv->layout_manager != NULL)
5199     {
5200       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5201       g_clear_object (&priv->layout_manager);
5202     }
5203
5204   if (priv->content != NULL)
5205     {
5206       _clutter_content_detached (priv->content, self);
5207       g_clear_object (&priv->content);
5208     }
5209
5210   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5211 }
5212
5213 static void
5214 clutter_actor_finalize (GObject *object)
5215 {
5216   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5217
5218   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5219                 priv->name != NULL ? priv->name : "<none>",
5220                 priv->id,
5221                 g_type_name (G_OBJECT_TYPE (object)));
5222
5223   _clutter_context_release_id (priv->id);
5224
5225   g_free (priv->name);
5226
5227   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5228 }
5229
5230
5231 /**
5232  * clutter_actor_get_accessible:
5233  * @self: a #ClutterActor
5234  *
5235  * Returns the accessible object that describes the actor to an
5236  * assistive technology.
5237  *
5238  * If no class-specific #AtkObject implementation is available for the
5239  * actor instance in question, it will inherit an #AtkObject
5240  * implementation from the first ancestor class for which such an
5241  * implementation is defined.
5242  *
5243  * The documentation of the <ulink
5244  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5245  * library contains more information about accessible objects and
5246  * their uses.
5247  *
5248  * Returns: (transfer none): the #AtkObject associated with @actor
5249  */
5250 AtkObject *
5251 clutter_actor_get_accessible (ClutterActor *self)
5252 {
5253   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5254
5255   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5256 }
5257
5258 static AtkObject *
5259 clutter_actor_real_get_accessible (ClutterActor *actor)
5260 {
5261   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5262 }
5263
5264 static AtkObject *
5265 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5266 {
5267   AtkObject *accessible;
5268
5269   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5270   if (accessible != NULL)
5271     g_object_ref (accessible);
5272
5273   return accessible;
5274 }
5275
5276 static void
5277 atk_implementor_iface_init (AtkImplementorIface *iface)
5278 {
5279   iface->ref_accessible = _clutter_actor_ref_accessible;
5280 }
5281
5282 static gboolean
5283 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5284                                            ClutterPaintVolume *volume)
5285 {
5286   ClutterActorPrivate *priv = self->priv;
5287   gboolean res = TRUE;
5288
5289   /* we start from the allocation */
5290   clutter_paint_volume_set_width (volume,
5291                                   priv->allocation.x2 - priv->allocation.x1);
5292   clutter_paint_volume_set_height (volume,
5293                                    priv->allocation.y2 - priv->allocation.y1);
5294
5295   /* if the actor has a clip set then we have a pretty definite
5296    * size for the paint volume: the actor cannot possibly paint
5297    * outside the clip region.
5298    */
5299   if (priv->clip_to_allocation)
5300     {
5301       /* the allocation has already been set, so we just flip the
5302        * return value
5303        */
5304       res = TRUE;
5305     }
5306   else
5307     {
5308       ClutterActor *child;
5309
5310       if (priv->has_clip &&
5311           priv->clip.width >= 0 &&
5312           priv->clip.height >= 0)
5313         {
5314           ClutterVertex origin;
5315
5316           origin.x = priv->clip.x;
5317           origin.y = priv->clip.y;
5318           origin.z = 0;
5319
5320           clutter_paint_volume_set_origin (volume, &origin);
5321           clutter_paint_volume_set_width (volume, priv->clip.width);
5322           clutter_paint_volume_set_height (volume, priv->clip.height);
5323
5324           res = TRUE;
5325         }
5326
5327       /* if we don't have children we just bail out here... */
5328       if (priv->n_children == 0)
5329         return res;
5330
5331       /* ...but if we have children then we ask for their paint volume in
5332        * our coordinates. if any of our children replies that it doesn't
5333        * have a paint volume, we bail out
5334        */
5335       for (child = priv->first_child;
5336            child != NULL;
5337            child = child->priv->next_sibling)
5338         {
5339           const ClutterPaintVolume *child_volume;
5340
5341           if (!CLUTTER_ACTOR_IS_MAPPED (child))
5342             continue;
5343
5344           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5345           if (child_volume == NULL)
5346             {
5347               res = FALSE;
5348               break;
5349             }
5350
5351           clutter_paint_volume_union (volume, child_volume);
5352           res = TRUE;
5353         }
5354     }
5355
5356   return res;
5357
5358 }
5359
5360 static gboolean
5361 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5362                                      ClutterPaintVolume *volume)
5363 {
5364   ClutterActorClass *klass;
5365   gboolean res;
5366
5367   klass = CLUTTER_ACTOR_GET_CLASS (self);
5368
5369   /* XXX - this thoroughly sucks, but we don't want to penalize users
5370    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5371    * redraw. This should go away in 2.0.
5372    */
5373   if (klass->paint == clutter_actor_real_paint &&
5374       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5375     {
5376       res = TRUE;
5377     }
5378   else
5379     {
5380       /* this is the default return value: we cannot know if a class
5381        * is going to paint outside its allocation, so we take the
5382        * conservative approach.
5383        */
5384       res = FALSE;
5385     }
5386
5387   /* update_default_paint_volume() should only fail if one of the children
5388    * reported an invalid, or no, paint volume
5389    */
5390   if (!clutter_actor_update_default_paint_volume (self, volume))
5391     return FALSE;
5392
5393   return res;
5394 }
5395
5396 /**
5397  * clutter_actor_get_default_paint_volume:
5398  * @self: a #ClutterActor
5399  *
5400  * Retrieves the default paint volume for @self.
5401  *
5402  * This function provides the same #ClutterPaintVolume that would be
5403  * computed by the default implementation inside #ClutterActor of the
5404  * #ClutterActorClass.get_paint_volume() virtual function.
5405  *
5406  * This function should only be used by #ClutterActor subclasses that
5407  * cannot chain up to the parent implementation when computing their
5408  * paint volume.
5409  *
5410  * Return value: (transfer none): a pointer to the default
5411  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5412  *   the actor could not compute a valid paint volume. The returned value
5413  *   is not guaranteed to be stable across multiple frames, so if you
5414  *   want to retain it, you will need to copy it using
5415  *   clutter_paint_volume_copy().
5416  *
5417  * Since: 1.10
5418  */
5419 const ClutterPaintVolume *
5420 clutter_actor_get_default_paint_volume (ClutterActor *self)
5421 {
5422   ClutterPaintVolume volume;
5423   ClutterPaintVolume *res;
5424
5425   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5426
5427   res = NULL;
5428   _clutter_paint_volume_init_static (&volume, self);
5429   if (clutter_actor_update_default_paint_volume (self, &volume))
5430     {
5431       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5432
5433       if (stage != NULL)
5434         {
5435           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5436           _clutter_paint_volume_copy_static (&volume, res);
5437         }
5438     }
5439
5440   clutter_paint_volume_free (&volume);
5441
5442   return res;
5443 }
5444
5445 static gboolean
5446 clutter_actor_real_has_overlaps (ClutterActor *self)
5447 {
5448   /* By default we'll assume that all actors need an offscreen redirect to get
5449    * the correct opacity. Actors such as ClutterTexture that would never need
5450    * an offscreen redirect can override this to return FALSE. */
5451   return TRUE;
5452 }
5453
5454 static void
5455 clutter_actor_real_destroy (ClutterActor *actor)
5456 {
5457   ClutterActorIter iter;
5458
5459   g_object_freeze_notify (G_OBJECT (actor));
5460
5461   clutter_actor_iter_init (&iter, actor);
5462   while (clutter_actor_iter_next (&iter, NULL))
5463     clutter_actor_iter_destroy (&iter);
5464
5465   g_object_thaw_notify (G_OBJECT (actor));
5466 }
5467
5468 static GObject *
5469 clutter_actor_constructor (GType gtype,
5470                            guint n_props,
5471                            GObjectConstructParam *props)
5472 {
5473   GObjectClass *gobject_class;
5474   ClutterActor *self;
5475   GObject *retval;
5476
5477   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5478   retval = gobject_class->constructor (gtype, n_props, props);
5479   self = CLUTTER_ACTOR (retval);
5480
5481   if (self->priv->layout_manager == NULL)
5482     {
5483       ClutterLayoutManager *default_layout;
5484
5485       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5486
5487       default_layout = clutter_fixed_layout_new ();
5488       clutter_actor_set_layout_manager (self, default_layout);
5489     }
5490
5491   return retval;
5492 }
5493
5494 static void
5495 clutter_actor_class_init (ClutterActorClass *klass)
5496 {
5497   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5498
5499   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5500   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5501   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5502   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5503
5504   object_class->constructor = clutter_actor_constructor;
5505   object_class->set_property = clutter_actor_set_property;
5506   object_class->get_property = clutter_actor_get_property;
5507   object_class->dispose = clutter_actor_dispose;
5508   object_class->finalize = clutter_actor_finalize;
5509
5510   klass->show = clutter_actor_real_show;
5511   klass->show_all = clutter_actor_show;
5512   klass->hide = clutter_actor_real_hide;
5513   klass->hide_all = clutter_actor_hide;
5514   klass->map = clutter_actor_real_map;
5515   klass->unmap = clutter_actor_real_unmap;
5516   klass->unrealize = clutter_actor_real_unrealize;
5517   klass->pick = clutter_actor_real_pick;
5518   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5519   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5520   klass->allocate = clutter_actor_real_allocate;
5521   klass->queue_redraw = clutter_actor_real_queue_redraw;
5522   klass->queue_relayout = clutter_actor_real_queue_relayout;
5523   klass->apply_transform = clutter_actor_real_apply_transform;
5524   klass->get_accessible = clutter_actor_real_get_accessible;
5525   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5526   klass->has_overlaps = clutter_actor_real_has_overlaps;
5527   klass->paint = clutter_actor_real_paint;
5528   klass->destroy = clutter_actor_real_destroy;
5529
5530   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5531
5532   /**
5533    * ClutterActor:x:
5534    *
5535    * X coordinate of the actor in pixels. If written, forces a fixed
5536    * position for the actor. If read, returns the fixed position if any,
5537    * otherwise the allocation if available, otherwise 0.
5538    *
5539    * The #ClutterActor:x property is animatable.
5540    */
5541   obj_props[PROP_X] =
5542     g_param_spec_float ("x",
5543                         P_("X coordinate"),
5544                         P_("X coordinate of the actor"),
5545                         -G_MAXFLOAT, G_MAXFLOAT,
5546                         0.0,
5547                         G_PARAM_READWRITE |
5548                         G_PARAM_STATIC_STRINGS |
5549                         CLUTTER_PARAM_ANIMATABLE);
5550
5551   /**
5552    * ClutterActor:y:
5553    *
5554    * Y coordinate of the actor in pixels. If written, forces a fixed
5555    * position for the actor.  If read, returns the fixed position if
5556    * any, otherwise the allocation if available, otherwise 0.
5557    *
5558    * The #ClutterActor:y property is animatable.
5559    */
5560   obj_props[PROP_Y] =
5561     g_param_spec_float ("y",
5562                         P_("Y coordinate"),
5563                         P_("Y coordinate of the actor"),
5564                         -G_MAXFLOAT, G_MAXFLOAT,
5565                         0.0,
5566                         G_PARAM_READWRITE |
5567                         G_PARAM_STATIC_STRINGS |
5568                         CLUTTER_PARAM_ANIMATABLE);
5569
5570   /**
5571    * ClutterActor:position:
5572    *
5573    * The position of the origin of the actor.
5574    *
5575    * This property is a shorthand for setting and getting the
5576    * #ClutterActor:x and #ClutterActor:y properties at the same
5577    * time.
5578    *
5579    * The #ClutterActor:position property is animatable.
5580    *
5581    * Since: 1.12
5582    */
5583   obj_props[PROP_POSITION] =
5584     g_param_spec_boxed ("position",
5585                         P_("Position"),
5586                         P_("The position of the origin of the actor"),
5587                         CLUTTER_TYPE_POINT,
5588                         G_PARAM_READWRITE |
5589                         G_PARAM_STATIC_STRINGS |
5590                         CLUTTER_PARAM_ANIMATABLE);
5591
5592   /**
5593    * ClutterActor:width:
5594    *
5595    * Width of the actor (in pixels). If written, forces the minimum and
5596    * natural size request of the actor to the given width. If read, returns
5597    * the allocated width if available, otherwise the width request.
5598    *
5599    * The #ClutterActor:width property is animatable.
5600    */
5601   obj_props[PROP_WIDTH] =
5602     g_param_spec_float ("width",
5603                         P_("Width"),
5604                         P_("Width of the actor"),
5605                         0.0, G_MAXFLOAT,
5606                         0.0,
5607                         G_PARAM_READWRITE |
5608                         G_PARAM_STATIC_STRINGS |
5609                         CLUTTER_PARAM_ANIMATABLE);
5610
5611   /**
5612    * ClutterActor:height:
5613    *
5614    * Height of the actor (in pixels).  If written, forces the minimum and
5615    * natural size request of the actor to the given height. If read, returns
5616    * the allocated height if available, otherwise the height request.
5617    *
5618    * The #ClutterActor:height property is animatable.
5619    */
5620   obj_props[PROP_HEIGHT] =
5621     g_param_spec_float ("height",
5622                         P_("Height"),
5623                         P_("Height of the actor"),
5624                         0.0, G_MAXFLOAT,
5625                         0.0,
5626                         G_PARAM_READWRITE |
5627                         G_PARAM_STATIC_STRINGS |
5628                         CLUTTER_PARAM_ANIMATABLE);
5629
5630   /**
5631    * ClutterActor:size:
5632    *
5633    * The size of the actor.
5634    *
5635    * This property is a shorthand for setting and getting the
5636    * #ClutterActor:width and #ClutterActor:height at the same time.
5637    *
5638    * The #ClutterActor:size property is animatable.
5639    *
5640    * Since: 1.12
5641    */
5642   obj_props[PROP_SIZE] =
5643     g_param_spec_boxed ("size",
5644                         P_("Size"),
5645                         P_("The size of the actor"),
5646                         CLUTTER_TYPE_SIZE,
5647                         G_PARAM_READWRITE |
5648                         G_PARAM_STATIC_STRINGS |
5649                         CLUTTER_PARAM_ANIMATABLE);
5650
5651   /**
5652    * ClutterActor:fixed-x:
5653    *
5654    * The fixed X position of the actor in pixels.
5655    *
5656    * Writing this property sets #ClutterActor:fixed-position-set
5657    * property as well, as a side effect
5658    *
5659    * Since: 0.8
5660    */
5661   obj_props[PROP_FIXED_X] =
5662     g_param_spec_float ("fixed-x",
5663                         P_("Fixed X"),
5664                         P_("Forced X position of the actor"),
5665                         -G_MAXFLOAT, G_MAXFLOAT,
5666                         0.0,
5667                         CLUTTER_PARAM_READWRITE);
5668
5669   /**
5670    * ClutterActor:fixed-y:
5671    *
5672    * The fixed Y position of the actor in pixels.
5673    *
5674    * Writing this property sets the #ClutterActor:fixed-position-set
5675    * property as well, as a side effect
5676    *
5677    * Since: 0.8
5678    */
5679   obj_props[PROP_FIXED_Y] =
5680     g_param_spec_float ("fixed-y",
5681                         P_("Fixed Y"),
5682                         P_("Forced Y position of the actor"),
5683                         -G_MAXFLOAT, G_MAXFLOAT,
5684                         0,
5685                         CLUTTER_PARAM_READWRITE);
5686
5687   /**
5688    * ClutterActor:fixed-position-set:
5689    *
5690    * This flag controls whether the #ClutterActor:fixed-x and
5691    * #ClutterActor:fixed-y properties are used
5692    *
5693    * Since: 0.8
5694    */
5695   obj_props[PROP_FIXED_POSITION_SET] =
5696     g_param_spec_boolean ("fixed-position-set",
5697                           P_("Fixed position set"),
5698                           P_("Whether to use fixed positioning for the actor"),
5699                           FALSE,
5700                           CLUTTER_PARAM_READWRITE);
5701
5702   /**
5703    * ClutterActor:min-width:
5704    *
5705    * A forced minimum width request for the actor, in pixels
5706    *
5707    * Writing this property sets the #ClutterActor:min-width-set property
5708    * as well, as a side effect.
5709    *
5710    *This property overrides the usual width request of the actor.
5711    *
5712    * Since: 0.8
5713    */
5714   obj_props[PROP_MIN_WIDTH] =
5715     g_param_spec_float ("min-width",
5716                         P_("Min Width"),
5717                         P_("Forced minimum width request for the actor"),
5718                         0.0, G_MAXFLOAT,
5719                         0.0,
5720                         CLUTTER_PARAM_READWRITE);
5721
5722   /**
5723    * ClutterActor:min-height:
5724    *
5725    * A forced minimum height request for the actor, in pixels
5726    *
5727    * Writing this property sets the #ClutterActor:min-height-set property
5728    * as well, as a side effect. This property overrides the usual height
5729    * request of the actor.
5730    *
5731    * Since: 0.8
5732    */
5733   obj_props[PROP_MIN_HEIGHT] =
5734     g_param_spec_float ("min-height",
5735                         P_("Min Height"),
5736                         P_("Forced minimum height request for the actor"),
5737                         0.0, G_MAXFLOAT,
5738                         0.0,
5739                         CLUTTER_PARAM_READWRITE);
5740
5741   /**
5742    * ClutterActor:natural-width:
5743    *
5744    * A forced natural width request for the actor, in pixels
5745    *
5746    * Writing this property sets the #ClutterActor:natural-width-set
5747    * property as well, as a side effect. This property overrides the
5748    * usual width request of the actor
5749    *
5750    * Since: 0.8
5751    */
5752   obj_props[PROP_NATURAL_WIDTH] =
5753     g_param_spec_float ("natural-width",
5754                         P_("Natural Width"),
5755                         P_("Forced natural width request for the actor"),
5756                         0.0, G_MAXFLOAT,
5757                         0.0,
5758                         CLUTTER_PARAM_READWRITE);
5759
5760   /**
5761    * ClutterActor:natural-height:
5762    *
5763    * A forced natural height request for the actor, in pixels
5764    *
5765    * Writing this property sets the #ClutterActor:natural-height-set
5766    * property as well, as a side effect. This property overrides the
5767    * usual height request of the actor
5768    *
5769    * Since: 0.8
5770    */
5771   obj_props[PROP_NATURAL_HEIGHT] =
5772     g_param_spec_float ("natural-height",
5773                         P_("Natural Height"),
5774                         P_("Forced natural height request for the actor"),
5775                         0.0, G_MAXFLOAT,
5776                         0.0,
5777                         CLUTTER_PARAM_READWRITE);
5778
5779   /**
5780    * ClutterActor:min-width-set:
5781    *
5782    * This flag controls whether the #ClutterActor:min-width property
5783    * is used
5784    *
5785    * Since: 0.8
5786    */
5787   obj_props[PROP_MIN_WIDTH_SET] =
5788     g_param_spec_boolean ("min-width-set",
5789                           P_("Minimum width set"),
5790                           P_("Whether to use the min-width property"),
5791                           FALSE,
5792                           CLUTTER_PARAM_READWRITE);
5793
5794   /**
5795    * ClutterActor:min-height-set:
5796    *
5797    * This flag controls whether the #ClutterActor:min-height property
5798    * is used
5799    *
5800    * Since: 0.8
5801    */
5802   obj_props[PROP_MIN_HEIGHT_SET] =
5803     g_param_spec_boolean ("min-height-set",
5804                           P_("Minimum height set"),
5805                           P_("Whether to use the min-height property"),
5806                           FALSE,
5807                           CLUTTER_PARAM_READWRITE);
5808
5809   /**
5810    * ClutterActor:natural-width-set:
5811    *
5812    * This flag controls whether the #ClutterActor:natural-width property
5813    * is used
5814    *
5815    * Since: 0.8
5816    */
5817   obj_props[PROP_NATURAL_WIDTH_SET] =
5818     g_param_spec_boolean ("natural-width-set",
5819                           P_("Natural width set"),
5820                           P_("Whether to use the natural-width property"),
5821                           FALSE,
5822                           CLUTTER_PARAM_READWRITE);
5823
5824   /**
5825    * ClutterActor:natural-height-set:
5826    *
5827    * This flag controls whether the #ClutterActor:natural-height property
5828    * is used
5829    *
5830    * Since: 0.8
5831    */
5832   obj_props[PROP_NATURAL_HEIGHT_SET] =
5833     g_param_spec_boolean ("natural-height-set",
5834                           P_("Natural height set"),
5835                           P_("Whether to use the natural-height property"),
5836                           FALSE,
5837                           CLUTTER_PARAM_READWRITE);
5838
5839   /**
5840    * ClutterActor:allocation:
5841    *
5842    * The allocation for the actor, in pixels
5843    *
5844    * This is property is read-only, but you might monitor it to know when an
5845    * actor moves or resizes
5846    *
5847    * Since: 0.8
5848    */
5849   obj_props[PROP_ALLOCATION] =
5850     g_param_spec_boxed ("allocation",
5851                         P_("Allocation"),
5852                         P_("The actor's allocation"),
5853                         CLUTTER_TYPE_ACTOR_BOX,
5854                         G_PARAM_READABLE |
5855                         G_PARAM_STATIC_STRINGS |
5856                         CLUTTER_PARAM_ANIMATABLE);
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 static void
8635 clutter_actor_allocate_internal (ClutterActor           *self,
8636                                  const ClutterActorBox  *allocation,
8637                                  ClutterAllocationFlags  flags)
8638 {
8639   ClutterActorClass *klass;
8640
8641   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8642
8643   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8644                 _clutter_actor_get_debug_name (self));
8645
8646   klass = CLUTTER_ACTOR_GET_CLASS (self);
8647   klass->allocate (self, allocation, flags);
8648
8649   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8650
8651   clutter_actor_queue_redraw (self);
8652 }
8653
8654 /**
8655  * clutter_actor_allocate:
8656  * @self: A #ClutterActor
8657  * @box: new allocation of the actor, in parent-relative coordinates
8658  * @flags: flags that control the allocation
8659  *
8660  * Called by the parent of an actor to assign the actor its size.
8661  * Should never be called by applications (except when implementing
8662  * a container or layout manager).
8663  *
8664  * Actors can know from their allocation box whether they have moved
8665  * with respect to their parent actor. The @flags parameter describes
8666  * additional information about the allocation, for instance whether
8667  * the parent has moved with respect to the stage, for example because
8668  * a grandparent's origin has moved.
8669  *
8670  * Since: 0.8
8671  */
8672 void
8673 clutter_actor_allocate (ClutterActor           *self,
8674                         const ClutterActorBox  *box,
8675                         ClutterAllocationFlags  flags)
8676 {
8677   ClutterActorBox old_allocation, real_allocation;
8678   gboolean origin_changed, child_moved, size_changed;
8679   gboolean stage_allocation_changed;
8680   ClutterActorPrivate *priv;
8681
8682   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8683   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8684     {
8685       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8686                  "which isn't a descendent of the stage!\n",
8687                  self, _clutter_actor_get_debug_name (self));
8688       return;
8689     }
8690
8691   priv = self->priv;
8692
8693   old_allocation = priv->allocation;
8694   real_allocation = *box;
8695
8696   /* constraints are allowed to modify the allocation only here; we do
8697    * this prior to all the other checks so that we can bail out if the
8698    * allocation did not change
8699    */
8700   clutter_actor_update_constraints (self, &real_allocation);
8701
8702   /* adjust the allocation depending on the align/margin properties */
8703   clutter_actor_adjust_allocation (self, &real_allocation);
8704
8705   if (real_allocation.x2 < real_allocation.x1 ||
8706       real_allocation.y2 < real_allocation.y1)
8707     {
8708       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8709                  _clutter_actor_get_debug_name (self),
8710                  real_allocation.x2 - real_allocation.x1,
8711                  real_allocation.y2 - real_allocation.y1);
8712     }
8713
8714   /* we allow 0-sized actors, but not negative-sized ones */
8715   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8716   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8717
8718   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8719
8720   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8721                  real_allocation.y1 != old_allocation.y1);
8722
8723   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8724                   real_allocation.y2 != old_allocation.y2);
8725
8726   if (origin_changed || child_moved || size_changed)
8727     stage_allocation_changed = TRUE;
8728   else
8729     stage_allocation_changed = FALSE;
8730
8731   /* If we get an allocation "out of the blue"
8732    * (we did not queue relayout), then we want to
8733    * ignore it. But if we have needs_allocation set,
8734    * we want to guarantee that allocate() virtual
8735    * method is always called, i.e. that queue_relayout()
8736    * always results in an allocate() invocation on
8737    * an actor.
8738    *
8739    * The optimization here is to avoid re-allocating
8740    * actors that did not queue relayout and were
8741    * not moved.
8742    */
8743   if (!priv->needs_allocation && !stage_allocation_changed)
8744     {
8745       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8746       return;
8747     }
8748
8749   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8750    * clutter_actor_allocate(), it indicates whether the parent has its
8751    * absolute origin moved; when passed in to ClutterActor::allocate()
8752    * virtual method though, it indicates whether the child has its
8753    * absolute origin moved.  So we set it when child_moved is TRUE
8754    */
8755   if (child_moved)
8756     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8757
8758   /* store the flags here, so that they can be propagated by the
8759    * transition code
8760    */
8761   self->priv->allocation_flags = flags;
8762
8763   if (_clutter_actor_get_transition (self, obj_props[PROP_ALLOCATION]) == NULL)
8764     {
8765       _clutter_actor_create_transition (self, obj_props[PROP_ALLOCATION],
8766                                         &priv->allocation,
8767                                         &real_allocation);
8768     }
8769   else
8770     _clutter_actor_update_transition (self, obj_props[PROP_ALLOCATION],
8771                                       &real_allocation);
8772 }
8773
8774 /**
8775  * clutter_actor_set_allocation:
8776  * @self: a #ClutterActor
8777  * @box: a #ClutterActorBox
8778  * @flags: allocation flags
8779  *
8780  * Stores the allocation of @self as defined by @box.
8781  *
8782  * This function can only be called from within the implementation of
8783  * the #ClutterActorClass.allocate() virtual function.
8784  *
8785  * The allocation should have been adjusted to take into account constraints,
8786  * alignment, and margin properties. If you are implementing a #ClutterActor
8787  * subclass that provides its own layout management policy for its children
8788  * instead of using a #ClutterLayoutManager delegate, you should not call
8789  * this function on the children of @self; instead, you should call
8790  * clutter_actor_allocate(), which will adjust the allocation box for
8791  * you.
8792  *
8793  * This function should only be used by subclasses of #ClutterActor
8794  * that wish to store their allocation but cannot chain up to the
8795  * parent's implementation; the default implementation of the
8796  * #ClutterActorClass.allocate() virtual function will call this
8797  * function.
8798  *
8799  * It is important to note that, while chaining up was the recommended
8800  * behaviour for #ClutterActor subclasses prior to the introduction of
8801  * this function, it is recommended to call clutter_actor_set_allocation()
8802  * instead.
8803  *
8804  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8805  * to handle the allocation of its children, this function will call
8806  * the clutter_layout_manager_allocate() function only if the
8807  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8808  * expected that the subclass will call clutter_layout_manager_allocate()
8809  * by itself. For instance, the following code:
8810  *
8811  * |[
8812  * static void
8813  * my_actor_allocate (ClutterActor *actor,
8814  *                    const ClutterActorBox *allocation,
8815  *                    ClutterAllocationFlags flags)
8816  * {
8817  *   ClutterActorBox new_alloc;
8818  *   ClutterAllocationFlags new_flags;
8819  *
8820  *   adjust_allocation (allocation, &amp;new_alloc);
8821  *
8822  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8823  *
8824  *   /&ast; this will use the layout manager set on the actor &ast;/
8825  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8826  * }
8827  * ]|
8828  *
8829  * is equivalent to this:
8830  *
8831  * |[
8832  * static void
8833  * my_actor_allocate (ClutterActor *actor,
8834  *                    const ClutterActorBox *allocation,
8835  *                    ClutterAllocationFlags flags)
8836  * {
8837  *   ClutterLayoutManager *layout;
8838  *   ClutterActorBox new_alloc;
8839  *
8840  *   adjust_allocation (allocation, &amp;new_alloc);
8841  *
8842  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8843  *
8844  *   layout = clutter_actor_get_layout_manager (actor);
8845  *   clutter_layout_manager_allocate (layout,
8846  *                                    CLUTTER_CONTAINER (actor),
8847  *                                    &amp;new_alloc,
8848  *                                    flags);
8849  * }
8850  * ]|
8851  *
8852  * Since: 1.10
8853  */
8854 void
8855 clutter_actor_set_allocation (ClutterActor           *self,
8856                               const ClutterActorBox  *box,
8857                               ClutterAllocationFlags  flags)
8858 {
8859   ClutterActorPrivate *priv;
8860   gboolean changed;
8861
8862   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8863   g_return_if_fail (box != NULL);
8864
8865   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8866     {
8867       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8868                   "can only be called from within the implementation of "
8869                   "the ClutterActor::allocate() virtual function.");
8870       return;
8871     }
8872
8873   priv = self->priv;
8874
8875   g_object_freeze_notify (G_OBJECT (self));
8876
8877   changed = clutter_actor_set_allocation_internal (self, box, flags);
8878
8879   /* we allocate our children before we notify changes in our geometry,
8880    * so that people connecting to properties will be able to get valid
8881    * data out of the sub-tree of the scene graph that has this actor at
8882    * the root.
8883    */
8884   clutter_actor_maybe_layout_children (self, box, flags);
8885
8886   if (changed)
8887     {
8888       ClutterActorBox signal_box = priv->allocation;
8889       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8890
8891       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8892                      &signal_box,
8893                      signal_flags);
8894     }
8895
8896   g_object_thaw_notify (G_OBJECT (self));
8897 }
8898
8899 /**
8900  * clutter_actor_set_geometry:
8901  * @self: A #ClutterActor
8902  * @geometry: A #ClutterGeometry
8903  *
8904  * Sets the actor's fixed position and forces its minimum and natural
8905  * size, in pixels. This means the untransformed actor will have the
8906  * given geometry. This is the same as calling clutter_actor_set_position()
8907  * and clutter_actor_set_size().
8908  *
8909  * Deprecated: 1.10: Use clutter_actor_set_position() and
8910  *   clutter_actor_set_size() instead.
8911  */
8912 void
8913 clutter_actor_set_geometry (ClutterActor          *self,
8914                             const ClutterGeometry *geometry)
8915 {
8916   g_object_freeze_notify (G_OBJECT (self));
8917
8918   clutter_actor_set_position (self, geometry->x, geometry->y);
8919   clutter_actor_set_size (self, geometry->width, geometry->height);
8920
8921   g_object_thaw_notify (G_OBJECT (self));
8922 }
8923
8924 /**
8925  * clutter_actor_get_geometry:
8926  * @self: A #ClutterActor
8927  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8928  *
8929  * Gets the size and position of an actor relative to its parent
8930  * actor. This is the same as calling clutter_actor_get_position() and
8931  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8932  * requested size and position if the actor's allocation is invalid.
8933  *
8934  * Deprecated: 1.10: Use clutter_actor_get_position() and
8935  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8936  *   instead.
8937  */
8938 void
8939 clutter_actor_get_geometry (ClutterActor    *self,
8940                             ClutterGeometry *geometry)
8941 {
8942   gfloat x, y, width, height;
8943
8944   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8945   g_return_if_fail (geometry != NULL);
8946
8947   clutter_actor_get_position (self, &x, &y);
8948   clutter_actor_get_size (self, &width, &height);
8949
8950   geometry->x = (int) x;
8951   geometry->y = (int) y;
8952   geometry->width = (int) width;
8953   geometry->height = (int) height;
8954 }
8955
8956 /**
8957  * clutter_actor_set_position:
8958  * @self: A #ClutterActor
8959  * @x: New left position of actor in pixels.
8960  * @y: New top position of actor in pixels.
8961  *
8962  * Sets the actor's fixed position in pixels relative to any parent
8963  * actor.
8964  *
8965  * If a layout manager is in use, this position will override the
8966  * layout manager and force a fixed position.
8967  */
8968 void
8969 clutter_actor_set_position (ClutterActor *self,
8970                             gfloat        x,
8971                             gfloat        y)
8972 {
8973   ClutterPoint new_position;
8974
8975   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8976
8977   clutter_point_init (&new_position, x, y);
8978
8979   if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
8980     {
8981       ClutterPoint cur_position;
8982
8983       cur_position.x = clutter_actor_get_x (self);
8984       cur_position.y = clutter_actor_get_y (self);
8985
8986       _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
8987                                         &cur_position,
8988                                         &new_position);
8989     }
8990   else
8991     _clutter_actor_update_transition (self,
8992                                       obj_props[PROP_POSITION],
8993                                       &new_position);
8994
8995   clutter_actor_queue_relayout (self);
8996 }
8997
8998 /**
8999  * clutter_actor_get_fixed_position_set:
9000  * @self: A #ClutterActor
9001  *
9002  * Checks whether an actor has a fixed position set (and will thus be
9003  * unaffected by any layout manager).
9004  *
9005  * Return value: %TRUE if the fixed position is set on the actor
9006  *
9007  * Since: 0.8
9008  */
9009 gboolean
9010 clutter_actor_get_fixed_position_set (ClutterActor *self)
9011 {
9012   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9013
9014   return self->priv->position_set;
9015 }
9016
9017 /**
9018  * clutter_actor_set_fixed_position_set:
9019  * @self: A #ClutterActor
9020  * @is_set: whether to use fixed position
9021  *
9022  * Sets whether an actor has a fixed position set (and will thus be
9023  * unaffected by any layout manager).
9024  *
9025  * Since: 0.8
9026  */
9027 void
9028 clutter_actor_set_fixed_position_set (ClutterActor *self,
9029                                       gboolean      is_set)
9030 {
9031   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9032
9033   if (self->priv->position_set == (is_set != FALSE))
9034     return;
9035
9036   self->priv->position_set = is_set != FALSE;
9037   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
9038
9039   clutter_actor_queue_relayout (self);
9040 }
9041
9042 /**
9043  * clutter_actor_move_by:
9044  * @self: A #ClutterActor
9045  * @dx: Distance to move Actor on X axis.
9046  * @dy: Distance to move Actor on Y axis.
9047  *
9048  * Moves an actor by the specified distance relative to its current
9049  * position in pixels.
9050  *
9051  * This function modifies the fixed position of an actor and thus removes
9052  * it from any layout management. Another way to move an actor is with an
9053  * anchor point, see clutter_actor_set_anchor_point().
9054  *
9055  * Since: 0.2
9056  */
9057 void
9058 clutter_actor_move_by (ClutterActor *self,
9059                        gfloat        dx,
9060                        gfloat        dy)
9061 {
9062   const ClutterLayoutInfo *info;
9063   gfloat x, y;
9064
9065   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9066
9067   info = _clutter_actor_get_layout_info_or_defaults (self);
9068   x = info->fixed_pos.x;
9069   y = info->fixed_pos.y;
9070
9071   clutter_actor_set_position (self, x + dx, y + dy);
9072 }
9073
9074 static void
9075 clutter_actor_set_min_width (ClutterActor *self,
9076                              gfloat        min_width)
9077 {
9078   ClutterActorPrivate *priv = self->priv;
9079   ClutterActorBox old = { 0, };
9080   ClutterLayoutInfo *info;
9081
9082   /* if we are setting the size on a top-level actor and the
9083    * backend only supports static top-levels (e.g. framebuffers)
9084    * then we ignore the passed value and we override it with
9085    * the stage implementation's preferred size.
9086    */
9087   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9088       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9089     return;
9090
9091   info = _clutter_actor_get_layout_info (self);
9092
9093   if (priv->min_width_set && min_width == info->minimum.width)
9094     return;
9095
9096   g_object_freeze_notify (G_OBJECT (self));
9097
9098   clutter_actor_store_old_geometry (self, &old);
9099
9100   info->minimum.width = min_width;
9101   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
9102   clutter_actor_set_min_width_set (self, TRUE);
9103
9104   clutter_actor_notify_if_geometry_changed (self, &old);
9105
9106   g_object_thaw_notify (G_OBJECT (self));
9107
9108   clutter_actor_queue_relayout (self);
9109 }
9110
9111 static void
9112 clutter_actor_set_min_height (ClutterActor *self,
9113                               gfloat        min_height)
9114
9115 {
9116   ClutterActorPrivate *priv = self->priv;
9117   ClutterActorBox old = { 0, };
9118   ClutterLayoutInfo *info;
9119
9120   /* if we are setting the size on a top-level actor and the
9121    * backend only supports static top-levels (e.g. framebuffers)
9122    * then we ignore the passed value and we override it with
9123    * the stage implementation's preferred size.
9124    */
9125   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9126       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9127     return;
9128
9129   info = _clutter_actor_get_layout_info (self);
9130
9131   if (priv->min_height_set && min_height == info->minimum.height)
9132     return;
9133
9134   g_object_freeze_notify (G_OBJECT (self));
9135
9136   clutter_actor_store_old_geometry (self, &old);
9137
9138   info->minimum.height = min_height;
9139   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
9140   clutter_actor_set_min_height_set (self, TRUE);
9141
9142   clutter_actor_notify_if_geometry_changed (self, &old);
9143
9144   g_object_thaw_notify (G_OBJECT (self));
9145
9146   clutter_actor_queue_relayout (self);
9147 }
9148
9149 static void
9150 clutter_actor_set_natural_width (ClutterActor *self,
9151                                  gfloat        natural_width)
9152 {
9153   ClutterActorPrivate *priv = self->priv;
9154   ClutterActorBox old = { 0, };
9155   ClutterLayoutInfo *info;
9156
9157   /* if we are setting the size on a top-level actor and the
9158    * backend only supports static top-levels (e.g. framebuffers)
9159    * then we ignore the passed value and we override it with
9160    * the stage implementation's preferred size.
9161    */
9162   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9163       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9164     return;
9165
9166   info = _clutter_actor_get_layout_info (self);
9167
9168   if (priv->natural_width_set && natural_width == info->natural.width)
9169     return;
9170
9171   g_object_freeze_notify (G_OBJECT (self));
9172
9173   clutter_actor_store_old_geometry (self, &old);
9174
9175   info->natural.width = natural_width;
9176   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9177   clutter_actor_set_natural_width_set (self, TRUE);
9178
9179   clutter_actor_notify_if_geometry_changed (self, &old);
9180
9181   g_object_thaw_notify (G_OBJECT (self));
9182
9183   clutter_actor_queue_relayout (self);
9184 }
9185
9186 static void
9187 clutter_actor_set_natural_height (ClutterActor *self,
9188                                   gfloat        natural_height)
9189 {
9190   ClutterActorPrivate *priv = self->priv;
9191   ClutterActorBox old = { 0, };
9192   ClutterLayoutInfo *info;
9193
9194   /* if we are setting the size on a top-level actor and the
9195    * backend only supports static top-levels (e.g. framebuffers)
9196    * then we ignore the passed value and we override it with
9197    * the stage implementation's preferred size.
9198    */
9199   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9200       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9201     return;
9202
9203   info = _clutter_actor_get_layout_info (self);
9204
9205   if (priv->natural_height_set && natural_height == info->natural.height)
9206     return;
9207
9208   g_object_freeze_notify (G_OBJECT (self));
9209
9210   clutter_actor_store_old_geometry (self, &old);
9211
9212   info->natural.height = natural_height;
9213   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9214   clutter_actor_set_natural_height_set (self, TRUE);
9215
9216   clutter_actor_notify_if_geometry_changed (self, &old);
9217
9218   g_object_thaw_notify (G_OBJECT (self));
9219
9220   clutter_actor_queue_relayout (self);
9221 }
9222
9223 static void
9224 clutter_actor_set_min_width_set (ClutterActor *self,
9225                                  gboolean      use_min_width)
9226 {
9227   ClutterActorPrivate *priv = self->priv;
9228   ClutterActorBox old = { 0, };
9229
9230   if (priv->min_width_set == (use_min_width != FALSE))
9231     return;
9232
9233   clutter_actor_store_old_geometry (self, &old);
9234
9235   priv->min_width_set = use_min_width != FALSE;
9236   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9237
9238   clutter_actor_notify_if_geometry_changed (self, &old);
9239
9240   clutter_actor_queue_relayout (self);
9241 }
9242
9243 static void
9244 clutter_actor_set_min_height_set (ClutterActor *self,
9245                                   gboolean      use_min_height)
9246 {
9247   ClutterActorPrivate *priv = self->priv;
9248   ClutterActorBox old = { 0, };
9249
9250   if (priv->min_height_set == (use_min_height != FALSE))
9251     return;
9252
9253   clutter_actor_store_old_geometry (self, &old);
9254
9255   priv->min_height_set = use_min_height != FALSE;
9256   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9257
9258   clutter_actor_notify_if_geometry_changed (self, &old);
9259
9260   clutter_actor_queue_relayout (self);
9261 }
9262
9263 static void
9264 clutter_actor_set_natural_width_set (ClutterActor *self,
9265                                      gboolean      use_natural_width)
9266 {
9267   ClutterActorPrivate *priv = self->priv;
9268   ClutterActorBox old = { 0, };
9269
9270   if (priv->natural_width_set == (use_natural_width != FALSE))
9271     return;
9272
9273   clutter_actor_store_old_geometry (self, &old);
9274
9275   priv->natural_width_set = use_natural_width != FALSE;
9276   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9277
9278   clutter_actor_notify_if_geometry_changed (self, &old);
9279
9280   clutter_actor_queue_relayout (self);
9281 }
9282
9283 static void
9284 clutter_actor_set_natural_height_set (ClutterActor *self,
9285                                       gboolean      use_natural_height)
9286 {
9287   ClutterActorPrivate *priv = self->priv;
9288   ClutterActorBox old = { 0, };
9289
9290   if (priv->natural_height_set == (use_natural_height != FALSE))
9291     return;
9292
9293   clutter_actor_store_old_geometry (self, &old);
9294
9295   priv->natural_height_set = use_natural_height != FALSE;
9296   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9297
9298   clutter_actor_notify_if_geometry_changed (self, &old);
9299
9300   clutter_actor_queue_relayout (self);
9301 }
9302
9303 /**
9304  * clutter_actor_set_request_mode:
9305  * @self: a #ClutterActor
9306  * @mode: the request mode
9307  *
9308  * Sets the geometry request mode of @self.
9309  *
9310  * The @mode determines the order for invoking
9311  * clutter_actor_get_preferred_width() and
9312  * clutter_actor_get_preferred_height()
9313  *
9314  * Since: 1.2
9315  */
9316 void
9317 clutter_actor_set_request_mode (ClutterActor       *self,
9318                                 ClutterRequestMode  mode)
9319 {
9320   ClutterActorPrivate *priv;
9321
9322   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9323
9324   priv = self->priv;
9325
9326   if (priv->request_mode == mode)
9327     return;
9328
9329   priv->request_mode = mode;
9330
9331   priv->needs_width_request = TRUE;
9332   priv->needs_height_request = TRUE;
9333
9334   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9335
9336   clutter_actor_queue_relayout (self);
9337 }
9338
9339 /**
9340  * clutter_actor_get_request_mode:
9341  * @self: a #ClutterActor
9342  *
9343  * Retrieves the geometry request mode of @self
9344  *
9345  * Return value: the request mode for the actor
9346  *
9347  * Since: 1.2
9348  */
9349 ClutterRequestMode
9350 clutter_actor_get_request_mode (ClutterActor *self)
9351 {
9352   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9353                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9354
9355   return self->priv->request_mode;
9356 }
9357
9358 /* variant of set_width() without checks and without notification
9359  * freeze+thaw, for internal usage only
9360  */
9361 static inline void
9362 clutter_actor_set_width_internal (ClutterActor *self,
9363                                   gfloat        width)
9364 {
9365   if (width >= 0)
9366     {
9367       /* the Stage will use the :min-width to control the minimum
9368        * width to be resized to, so we should not be setting it
9369        * along with the :natural-width
9370        */
9371       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9372         clutter_actor_set_min_width (self, width);
9373
9374       clutter_actor_set_natural_width (self, width);
9375     }
9376   else
9377     {
9378       /* we only unset the :natural-width for the Stage */
9379       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9380         clutter_actor_set_min_width_set (self, FALSE);
9381
9382       clutter_actor_set_natural_width_set (self, FALSE);
9383     }
9384 }
9385
9386 /* variant of set_height() without checks and without notification
9387  * freeze+thaw, for internal usage only
9388  */
9389 static inline void
9390 clutter_actor_set_height_internal (ClutterActor *self,
9391                                    gfloat        height)
9392 {
9393   if (height >= 0)
9394     {
9395       /* see the comment above in set_width_internal() */
9396       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9397         clutter_actor_set_min_height (self, height);
9398
9399       clutter_actor_set_natural_height (self, height);
9400     }
9401   else
9402     {
9403       /* see the comment above in set_width_internal() */
9404       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9405         clutter_actor_set_min_height_set (self, FALSE);
9406
9407       clutter_actor_set_natural_height_set (self, FALSE);
9408     }
9409 }
9410
9411 static void
9412 clutter_actor_set_size_internal (ClutterActor      *self,
9413                                  const ClutterSize *size)
9414 {
9415   if (size != NULL)
9416     {
9417       clutter_actor_set_width_internal (self, size->width);
9418       clutter_actor_set_height_internal (self, size->height);
9419     }
9420   else
9421     {
9422       clutter_actor_set_width_internal (self, -1);
9423       clutter_actor_set_height_internal (self, -1);
9424     }
9425 }
9426
9427 /**
9428  * clutter_actor_set_size:
9429  * @self: A #ClutterActor
9430  * @width: New width of actor in pixels, or -1
9431  * @height: New height of actor in pixels, or -1
9432  *
9433  * Sets the actor's size request in pixels. This overrides any
9434  * "normal" size request the actor would have. For example
9435  * a text actor might normally request the size of the text;
9436  * this function would force a specific size instead.
9437  *
9438  * If @width and/or @height are -1 the actor will use its
9439  * "normal" size request instead of overriding it, i.e.
9440  * you can "unset" the size with -1.
9441  *
9442  * This function sets or unsets both the minimum and natural size.
9443  */
9444 void
9445 clutter_actor_set_size (ClutterActor *self,
9446                         gfloat        width,
9447                         gfloat        height)
9448 {
9449   ClutterSize new_size;
9450
9451   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9452
9453   clutter_size_init (&new_size, width, height);
9454
9455   if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9456     {
9457       /* minor optimization: if we don't have a duration then we can
9458        * skip the get_size() below, to avoid the chance of going through
9459        * get_preferred_width() and get_preferred_height() just to jump to
9460        * a new desired size
9461        */
9462       if (clutter_actor_get_easing_duration (self) == 0)
9463         {
9464           g_object_freeze_notify (G_OBJECT (self));
9465
9466           clutter_actor_set_size_internal (self, &new_size);
9467
9468           g_object_thaw_notify (G_OBJECT (self));
9469
9470           return;
9471         }
9472       else
9473         {
9474           ClutterSize cur_size;
9475
9476           clutter_size_init (&cur_size,
9477                              clutter_actor_get_width (self),
9478                              clutter_actor_get_height (self));
9479
9480          _clutter_actor_create_transition (self,
9481                                            obj_props[PROP_SIZE],
9482                                            &cur_size,
9483                                            &new_size);
9484         }
9485     }
9486   else
9487     _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9488
9489   clutter_actor_queue_relayout (self);
9490 }
9491
9492 /**
9493  * clutter_actor_get_size:
9494  * @self: A #ClutterActor
9495  * @width: (out) (allow-none): return location for the width, or %NULL.
9496  * @height: (out) (allow-none): return location for the height, or %NULL.
9497  *
9498  * This function tries to "do what you mean" and return
9499  * the size an actor will have. If the actor has a valid
9500  * allocation, the allocation will be returned; otherwise,
9501  * the actors natural size request will be returned.
9502  *
9503  * If you care whether you get the request vs. the allocation, you
9504  * should probably call a different function like
9505  * clutter_actor_get_allocation_box() or
9506  * clutter_actor_get_preferred_width().
9507  *
9508  * Since: 0.2
9509  */
9510 void
9511 clutter_actor_get_size (ClutterActor *self,
9512                         gfloat       *width,
9513                         gfloat       *height)
9514 {
9515   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9516
9517   if (width)
9518     *width = clutter_actor_get_width (self);
9519
9520   if (height)
9521     *height = clutter_actor_get_height (self);
9522 }
9523
9524 /**
9525  * clutter_actor_get_position:
9526  * @self: a #ClutterActor
9527  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9528  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9529  *
9530  * This function tries to "do what you mean" and tell you where the
9531  * actor is, prior to any transformations. Retrieves the fixed
9532  * position of an actor in pixels, if one has been set; otherwise, if
9533  * the allocation is valid, returns the actor's allocated position;
9534  * otherwise, returns 0,0.
9535  *
9536  * The returned position is in pixels.
9537  *
9538  * Since: 0.6
9539  */
9540 void
9541 clutter_actor_get_position (ClutterActor *self,
9542                             gfloat       *x,
9543                             gfloat       *y)
9544 {
9545   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9546
9547   if (x)
9548     *x = clutter_actor_get_x (self);
9549
9550   if (y)
9551     *y = clutter_actor_get_y (self);
9552 }
9553
9554 /**
9555  * clutter_actor_get_transformed_position:
9556  * @self: A #ClutterActor
9557  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9558  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9559  *
9560  * Gets the absolute position of an actor, in pixels relative to the stage.
9561  *
9562  * Since: 0.8
9563  */
9564 void
9565 clutter_actor_get_transformed_position (ClutterActor *self,
9566                                         gfloat       *x,
9567                                         gfloat       *y)
9568 {
9569   ClutterVertex v1;
9570   ClutterVertex v2;
9571
9572   v1.x = v1.y = v1.z = 0;
9573   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9574
9575   if (x)
9576     *x = v2.x;
9577
9578   if (y)
9579     *y = v2.y;
9580 }
9581
9582 /**
9583  * clutter_actor_get_transformed_size:
9584  * @self: A #ClutterActor
9585  * @width: (out) (allow-none): return location for the width, or %NULL
9586  * @height: (out) (allow-none): return location for the height, or %NULL
9587  *
9588  * Gets the absolute size of an actor in pixels, taking into account the
9589  * scaling factors.
9590  *
9591  * If the actor has a valid allocation, the allocated size will be used.
9592  * If the actor has not a valid allocation then the preferred size will
9593  * be transformed and returned.
9594  *
9595  * If you want the transformed allocation, see
9596  * clutter_actor_get_abs_allocation_vertices() instead.
9597  *
9598  * <note>When the actor (or one of its ancestors) is rotated around the
9599  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9600  * as a generic quadrangle; in that case this function returns the size
9601  * of the smallest rectangle that encapsulates the entire quad. Please
9602  * note that in this case no assumptions can be made about the relative
9603  * position of this envelope to the absolute position of the actor, as
9604  * returned by clutter_actor_get_transformed_position(); if you need this
9605  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9606  * to get the coords of the actual quadrangle.</note>
9607  *
9608  * Since: 0.8
9609  */
9610 void
9611 clutter_actor_get_transformed_size (ClutterActor *self,
9612                                     gfloat       *width,
9613                                     gfloat       *height)
9614 {
9615   ClutterActorPrivate *priv;
9616   ClutterVertex v[4];
9617   gfloat x_min, x_max, y_min, y_max;
9618   gint i;
9619
9620   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9621
9622   priv = self->priv;
9623
9624   /* if the actor hasn't been allocated yet, get the preferred
9625    * size and transform that
9626    */
9627   if (priv->needs_allocation)
9628     {
9629       gfloat natural_width, natural_height;
9630       ClutterActorBox box;
9631
9632       /* Make a fake allocation to transform.
9633        *
9634        * NB: _clutter_actor_transform_and_project_box expects a box in
9635        * the actor's coordinate space... */
9636
9637       box.x1 = 0;
9638       box.y1 = 0;
9639
9640       natural_width = natural_height = 0;
9641       clutter_actor_get_preferred_size (self, NULL, NULL,
9642                                         &natural_width,
9643                                         &natural_height);
9644
9645       box.x2 = natural_width;
9646       box.y2 = natural_height;
9647
9648       _clutter_actor_transform_and_project_box (self, &box, v);
9649     }
9650   else
9651     clutter_actor_get_abs_allocation_vertices (self, v);
9652
9653   x_min = x_max = v[0].x;
9654   y_min = y_max = v[0].y;
9655
9656   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9657     {
9658       if (v[i].x < x_min)
9659         x_min = v[i].x;
9660
9661       if (v[i].x > x_max)
9662         x_max = v[i].x;
9663
9664       if (v[i].y < y_min)
9665         y_min = v[i].y;
9666
9667       if (v[i].y > y_max)
9668         y_max = v[i].y;
9669     }
9670
9671   if (width)
9672     *width  = x_max - x_min;
9673
9674   if (height)
9675     *height = y_max - y_min;
9676 }
9677
9678 /**
9679  * clutter_actor_get_width:
9680  * @self: A #ClutterActor
9681  *
9682  * Retrieves the width of a #ClutterActor.
9683  *
9684  * If the actor has a valid allocation, this function will return the
9685  * width of the allocated area given to the actor.
9686  *
9687  * If the actor does not have a valid allocation, this function will
9688  * return the actor's natural width, that is the preferred width of
9689  * the actor.
9690  *
9691  * If you care whether you get the preferred width or the width that
9692  * has been assigned to the actor, you should probably call a different
9693  * function like clutter_actor_get_allocation_box() to retrieve the
9694  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9695  * preferred width.
9696  *
9697  * If an actor has a fixed width, for instance a width that has been
9698  * assigned using clutter_actor_set_width(), the width returned will
9699  * be the same value.
9700  *
9701  * Return value: the width of the actor, in pixels
9702  */
9703 gfloat
9704 clutter_actor_get_width (ClutterActor *self)
9705 {
9706   ClutterActorPrivate *priv;
9707
9708   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9709
9710   priv = self->priv;
9711
9712   if (priv->needs_allocation)
9713     {
9714       gfloat natural_width = 0;
9715
9716       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9717         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9718       else
9719         {
9720           gfloat natural_height = 0;
9721
9722           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9723           clutter_actor_get_preferred_width (self, natural_height,
9724                                              NULL,
9725                                              &natural_width);
9726         }
9727
9728       return natural_width;
9729     }
9730   else
9731     return priv->allocation.x2 - priv->allocation.x1;
9732 }
9733
9734 /**
9735  * clutter_actor_get_height:
9736  * @self: A #ClutterActor
9737  *
9738  * Retrieves the height of a #ClutterActor.
9739  *
9740  * If the actor has a valid allocation, this function will return the
9741  * height of the allocated area given to the actor.
9742  *
9743  * If the actor does not have a valid allocation, this function will
9744  * return the actor's natural height, that is the preferred height of
9745  * the actor.
9746  *
9747  * If you care whether you get the preferred height or the height that
9748  * has been assigned to the actor, you should probably call a different
9749  * function like clutter_actor_get_allocation_box() to retrieve the
9750  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9751  * preferred height.
9752  *
9753  * If an actor has a fixed height, for instance a height that has been
9754  * assigned using clutter_actor_set_height(), the height returned will
9755  * be the same value.
9756  *
9757  * Return value: the height of the actor, in pixels
9758  */
9759 gfloat
9760 clutter_actor_get_height (ClutterActor *self)
9761 {
9762   ClutterActorPrivate *priv;
9763
9764   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9765
9766   priv = self->priv;
9767
9768   if (priv->needs_allocation)
9769     {
9770       gfloat natural_height = 0;
9771
9772       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9773         {
9774           gfloat natural_width = 0;
9775
9776           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9777           clutter_actor_get_preferred_height (self, natural_width,
9778                                               NULL, &natural_height);
9779         }
9780       else
9781         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9782
9783       return natural_height;
9784     }
9785   else
9786     return priv->allocation.y2 - priv->allocation.y1;
9787 }
9788
9789 /**
9790  * clutter_actor_set_width:
9791  * @self: A #ClutterActor
9792  * @width: Requested new width for the actor, in pixels, or -1
9793  *
9794  * Forces a width on an actor, causing the actor's preferred width
9795  * and height (if any) to be ignored.
9796  *
9797  * If @width is -1 the actor will use its preferred width request
9798  * instead of overriding it, i.e. you can "unset" the width with -1.
9799  *
9800  * This function sets both the minimum and natural size of the actor.
9801  *
9802  * since: 0.2
9803  */
9804 void
9805 clutter_actor_set_width (ClutterActor *self,
9806                          gfloat        width)
9807 {
9808   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9809
9810   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9811     {
9812       float cur_size;
9813
9814       /* minor optimization: if we don't have a duration
9815        * then we can skip the get_width() below, to avoid
9816        * the chance of going through get_preferred_width()
9817        * just to jump to a new desired width.
9818        */
9819       if (clutter_actor_get_easing_duration (self) == 0)
9820         {
9821           g_object_freeze_notify (G_OBJECT (self));
9822
9823           clutter_actor_set_width_internal (self, width);
9824
9825           g_object_thaw_notify (G_OBJECT (self));
9826
9827           return;
9828         }
9829       else
9830         cur_size = clutter_actor_get_width (self);
9831
9832       _clutter_actor_create_transition (self,
9833                                         obj_props[PROP_WIDTH],
9834                                         cur_size,
9835                                         width);
9836     }
9837   else
9838     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9839 }
9840
9841 /**
9842  * clutter_actor_set_height:
9843  * @self: A #ClutterActor
9844  * @height: Requested new height for the actor, in pixels, or -1
9845  *
9846  * Forces a height on an actor, causing the actor's preferred width
9847  * and height (if any) to be ignored.
9848  *
9849  * If @height is -1 the actor will use its preferred height instead of
9850  * overriding it, i.e. you can "unset" the height with -1.
9851  *
9852  * This function sets both the minimum and natural size of the actor.
9853  *
9854  * since: 0.2
9855  */
9856 void
9857 clutter_actor_set_height (ClutterActor *self,
9858                           gfloat        height)
9859 {
9860   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9861
9862   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9863     {
9864       float cur_size;
9865
9866       /* see the comment in clutter_actor_set_width() above */
9867       if (clutter_actor_get_easing_duration (self) == 0)
9868         {
9869           g_object_freeze_notify (G_OBJECT (self));
9870
9871           clutter_actor_set_height_internal (self, height);
9872
9873           g_object_thaw_notify (G_OBJECT (self));
9874
9875           return;
9876         }
9877       else
9878         cur_size = clutter_actor_get_height (self);
9879
9880       _clutter_actor_create_transition (self,
9881                                         obj_props[PROP_HEIGHT],
9882                                         cur_size,
9883                                         height);
9884     }
9885   else
9886     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9887 }
9888
9889 static inline void
9890 clutter_actor_set_x_internal (ClutterActor *self,
9891                               float         x)
9892 {
9893   ClutterActorPrivate *priv = self->priv;
9894   ClutterLayoutInfo *linfo;
9895   ClutterActorBox old = { 0, };
9896
9897   linfo = _clutter_actor_get_layout_info (self);
9898
9899   if (priv->position_set && linfo->fixed_pos.x == x)
9900     return;
9901
9902   clutter_actor_store_old_geometry (self, &old);
9903
9904   linfo->fixed_pos.x = x;
9905   clutter_actor_set_fixed_position_set (self, TRUE);
9906
9907   clutter_actor_notify_if_geometry_changed (self, &old);
9908
9909   clutter_actor_queue_relayout (self);
9910 }
9911
9912 static inline void
9913 clutter_actor_set_y_internal (ClutterActor *self,
9914                               float         y)
9915 {
9916   ClutterActorPrivate *priv = self->priv;
9917   ClutterLayoutInfo *linfo;
9918   ClutterActorBox old = { 0, };
9919
9920   linfo = _clutter_actor_get_layout_info (self);
9921
9922   if (priv->position_set && linfo->fixed_pos.y == y)
9923     return;
9924
9925   clutter_actor_store_old_geometry (self, &old);
9926
9927   linfo->fixed_pos.y = y;
9928   clutter_actor_set_fixed_position_set (self, TRUE);
9929
9930   clutter_actor_notify_if_geometry_changed (self, &old);
9931
9932   clutter_actor_queue_relayout (self);
9933 }
9934
9935 static void
9936 clutter_actor_set_position_internal (ClutterActor       *self,
9937                                      const ClutterPoint *position)
9938 {
9939   ClutterActorPrivate *priv = self->priv;
9940   ClutterLayoutInfo *linfo;
9941   ClutterActorBox old = { 0, };
9942
9943   linfo = _clutter_actor_get_layout_info (self);
9944
9945   if (priv->position_set &&
9946       clutter_point_equals (position, &linfo->fixed_pos))
9947     return;
9948
9949   clutter_actor_store_old_geometry (self, &old);
9950
9951   if (position != NULL)
9952     {
9953       linfo->fixed_pos = *position;
9954       clutter_actor_set_fixed_position_set (self, TRUE);
9955     }
9956   else
9957     clutter_actor_set_fixed_position_set (self, FALSE);
9958
9959   clutter_actor_notify_if_geometry_changed (self, &old);
9960
9961   clutter_actor_queue_relayout (self);
9962 }
9963
9964 /**
9965  * clutter_actor_set_x:
9966  * @self: a #ClutterActor
9967  * @x: the actor's position on the X axis
9968  *
9969  * Sets the actor's X coordinate, relative to its parent, in pixels.
9970  *
9971  * Overrides any layout manager and forces a fixed position for
9972  * the actor.
9973  *
9974  * The #ClutterActor:x property is animatable.
9975  *
9976  * Since: 0.6
9977  */
9978 void
9979 clutter_actor_set_x (ClutterActor *self,
9980                      gfloat        x)
9981 {
9982   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9983
9984   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9985     {
9986       float cur_position = clutter_actor_get_x (self);
9987
9988       _clutter_actor_create_transition (self, obj_props[PROP_X],
9989                                         cur_position,
9990                                         x);
9991     }
9992   else
9993     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9994 }
9995
9996 /**
9997  * clutter_actor_set_y:
9998  * @self: a #ClutterActor
9999  * @y: the actor's position on the Y axis
10000  *
10001  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
10002  *
10003  * Overrides any layout manager and forces a fixed position for
10004  * the actor.
10005  *
10006  * The #ClutterActor:y property is animatable.
10007  *
10008  * Since: 0.6
10009  */
10010 void
10011 clutter_actor_set_y (ClutterActor *self,
10012                      gfloat        y)
10013 {
10014   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10015
10016   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
10017     {
10018       float cur_position = clutter_actor_get_y (self);
10019
10020       _clutter_actor_create_transition (self, obj_props[PROP_Y],
10021                                         cur_position,
10022                                         y);
10023     }
10024   else
10025     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
10026 }
10027
10028 /**
10029  * clutter_actor_get_x:
10030  * @self: A #ClutterActor
10031  *
10032  * Retrieves the X coordinate of a #ClutterActor.
10033  *
10034  * This function tries to "do what you mean", by returning the
10035  * correct value depending on the actor's state.
10036  *
10037  * If the actor has a valid allocation, this function will return
10038  * the X coordinate of the origin of the allocation box.
10039  *
10040  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
10041  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10042  * function will return that coordinate.
10043  *
10044  * If both the allocation and a fixed position are missing, this function
10045  * will return 0.
10046  *
10047  * Return value: the X coordinate, in pixels, ignoring any
10048  *   transformation (i.e. scaling, rotation)
10049  */
10050 gfloat
10051 clutter_actor_get_x (ClutterActor *self)
10052 {
10053   ClutterActorPrivate *priv;
10054
10055   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10056
10057   priv = self->priv;
10058
10059   if (priv->needs_allocation)
10060     {
10061       if (priv->position_set)
10062         {
10063           const ClutterLayoutInfo *info;
10064
10065           info = _clutter_actor_get_layout_info_or_defaults (self);
10066
10067           return info->fixed_pos.x;
10068         }
10069       else
10070         return 0;
10071     }
10072   else
10073     return priv->allocation.x1;
10074 }
10075
10076 /**
10077  * clutter_actor_get_y:
10078  * @self: A #ClutterActor
10079  *
10080  * Retrieves the Y coordinate of a #ClutterActor.
10081  *
10082  * This function tries to "do what you mean", by returning the
10083  * correct value depending on the actor's state.
10084  *
10085  * If the actor has a valid allocation, this function will return
10086  * the Y coordinate of the origin of the allocation box.
10087  *
10088  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
10089  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10090  * function will return that coordinate.
10091  *
10092  * If both the allocation and a fixed position are missing, this function
10093  * will return 0.
10094  *
10095  * Return value: the Y coordinate, in pixels, ignoring any
10096  *   transformation (i.e. scaling, rotation)
10097  */
10098 gfloat
10099 clutter_actor_get_y (ClutterActor *self)
10100 {
10101   ClutterActorPrivate *priv;
10102
10103   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10104
10105   priv = self->priv;
10106
10107   if (priv->needs_allocation)
10108     {
10109       if (priv->position_set)
10110         {
10111           const ClutterLayoutInfo *info;
10112
10113           info = _clutter_actor_get_layout_info_or_defaults (self);
10114
10115           return info->fixed_pos.y;
10116         }
10117       else
10118         return 0;
10119     }
10120   else
10121     return priv->allocation.y1;
10122 }
10123
10124 /**
10125  * clutter_actor_set_scale:
10126  * @self: A #ClutterActor
10127  * @scale_x: double factor to scale actor by horizontally.
10128  * @scale_y: double factor to scale actor by vertically.
10129  *
10130  * Scales an actor with the given factors. The scaling is relative to
10131  * the scale center and the anchor point. The scale center is
10132  * unchanged by this function and defaults to 0,0.
10133  *
10134  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10135  * animatable.
10136  *
10137  * Since: 0.2
10138  */
10139 void
10140 clutter_actor_set_scale (ClutterActor *self,
10141                          gdouble       scale_x,
10142                          gdouble       scale_y)
10143 {
10144   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10145
10146   g_object_freeze_notify (G_OBJECT (self));
10147
10148   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10149   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10150
10151   g_object_thaw_notify (G_OBJECT (self));
10152 }
10153
10154 /**
10155  * clutter_actor_set_scale_full:
10156  * @self: A #ClutterActor
10157  * @scale_x: double factor to scale actor by horizontally.
10158  * @scale_y: double factor to scale actor by vertically.
10159  * @center_x: X coordinate of the center of the scale.
10160  * @center_y: Y coordinate of the center of the scale
10161  *
10162  * Scales an actor with the given factors around the given center
10163  * point. The center point is specified in pixels relative to the
10164  * anchor point (usually the top left corner of the actor).
10165  *
10166  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10167  * are animatable.
10168  *
10169  * Since: 1.0
10170  */
10171 void
10172 clutter_actor_set_scale_full (ClutterActor *self,
10173                               gdouble       scale_x,
10174                               gdouble       scale_y,
10175                               gfloat        center_x,
10176                               gfloat        center_y)
10177 {
10178   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10179
10180   g_object_freeze_notify (G_OBJECT (self));
10181
10182   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10183   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10184   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10185   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10186
10187   g_object_thaw_notify (G_OBJECT (self));
10188 }
10189
10190 /**
10191  * clutter_actor_set_scale_with_gravity:
10192  * @self: A #ClutterActor
10193  * @scale_x: double factor to scale actor by horizontally.
10194  * @scale_y: double factor to scale actor by vertically.
10195  * @gravity: the location of the scale center expressed as a compass
10196  * direction.
10197  *
10198  * Scales an actor with the given factors around the given
10199  * center point. The center point is specified as one of the compass
10200  * directions in #ClutterGravity. For example, setting it to north
10201  * will cause the top of the actor to remain unchanged and the rest of
10202  * the actor to expand left, right and downwards.
10203  *
10204  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10205  * animatable.
10206  *
10207  * Since: 1.0
10208  */
10209 void
10210 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
10211                                       gdouble         scale_x,
10212                                       gdouble         scale_y,
10213                                       ClutterGravity  gravity)
10214 {
10215   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10216
10217   g_object_freeze_notify (G_OBJECT (self));
10218
10219   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10220   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10221   clutter_actor_set_scale_gravity (self, gravity);
10222
10223   g_object_thaw_notify (G_OBJECT (self));
10224 }
10225
10226 /**
10227  * clutter_actor_get_scale:
10228  * @self: A #ClutterActor
10229  * @scale_x: (out) (allow-none): Location to store horizonal
10230  *   scale factor, or %NULL.
10231  * @scale_y: (out) (allow-none): Location to store vertical
10232  *   scale factor, or %NULL.
10233  *
10234  * Retrieves an actors scale factors.
10235  *
10236  * Since: 0.2
10237  */
10238 void
10239 clutter_actor_get_scale (ClutterActor *self,
10240                          gdouble      *scale_x,
10241                          gdouble      *scale_y)
10242 {
10243   const ClutterTransformInfo *info;
10244
10245   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10246
10247   info = _clutter_actor_get_transform_info_or_defaults (self);
10248
10249   if (scale_x)
10250     *scale_x = info->scale_x;
10251
10252   if (scale_y)
10253     *scale_y = info->scale_y;
10254 }
10255
10256 /**
10257  * clutter_actor_get_scale_center:
10258  * @self: A #ClutterActor
10259  * @center_x: (out) (allow-none): Location to store the X position
10260  *   of the scale center, or %NULL.
10261  * @center_y: (out) (allow-none): Location to store the Y position
10262  *   of the scale center, or %NULL.
10263  *
10264  * Retrieves the scale center coordinate in pixels relative to the top
10265  * left corner of the actor. If the scale center was specified using a
10266  * #ClutterGravity this will calculate the pixel offset using the
10267  * current size of the actor.
10268  *
10269  * Since: 1.0
10270  */
10271 void
10272 clutter_actor_get_scale_center (ClutterActor *self,
10273                                 gfloat       *center_x,
10274                                 gfloat       *center_y)
10275 {
10276   const ClutterTransformInfo *info;
10277
10278   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10279
10280   info = _clutter_actor_get_transform_info_or_defaults (self);
10281
10282   clutter_anchor_coord_get_units (self, &info->scale_center,
10283                                   center_x,
10284                                   center_y,
10285                                   NULL);
10286 }
10287
10288 /**
10289  * clutter_actor_get_scale_gravity:
10290  * @self: A #ClutterActor
10291  *
10292  * Retrieves the scale center as a compass direction. If the scale
10293  * center was specified in pixels or units this will return
10294  * %CLUTTER_GRAVITY_NONE.
10295  *
10296  * Return value: the scale gravity
10297  *
10298  * Since: 1.0
10299  */
10300 ClutterGravity
10301 clutter_actor_get_scale_gravity (ClutterActor *self)
10302 {
10303   const ClutterTransformInfo *info;
10304
10305   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10306
10307   info = _clutter_actor_get_transform_info_or_defaults (self);
10308
10309   return clutter_anchor_coord_get_gravity (&info->scale_center);
10310 }
10311
10312 static inline void
10313 clutter_actor_set_opacity_internal (ClutterActor *self,
10314                                     guint8        opacity)
10315 {
10316   ClutterActorPrivate *priv = self->priv;
10317
10318   if (priv->opacity != opacity)
10319     {
10320       priv->opacity = opacity;
10321
10322       /* Queue a redraw from the flatten effect so that it can use
10323          its cached image if available instead of having to redraw the
10324          actual actor. If it doesn't end up using the FBO then the
10325          effect is still able to continue the paint anyway. If there
10326          is no flatten effect yet then this is equivalent to queueing
10327          a full redraw */
10328       _clutter_actor_queue_redraw_full (self,
10329                                         0, /* flags */
10330                                         NULL, /* clip */
10331                                         priv->flatten_effect);
10332
10333       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10334     }
10335 }
10336
10337 /**
10338  * clutter_actor_set_opacity:
10339  * @self: A #ClutterActor
10340  * @opacity: New opacity value for the actor.
10341  *
10342  * Sets the actor's opacity, with zero being completely transparent and
10343  * 255 (0xff) being fully opaque.
10344  *
10345  * The #ClutterActor:opacity property is animatable.
10346  */
10347 void
10348 clutter_actor_set_opacity (ClutterActor *self,
10349                            guint8        opacity)
10350 {
10351   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10352
10353   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10354     {
10355       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10356                                         self->priv->opacity,
10357                                         opacity);
10358     }
10359   else
10360     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10361 }
10362
10363 /*
10364  * clutter_actor_get_paint_opacity_internal:
10365  * @self: a #ClutterActor
10366  *
10367  * Retrieves the absolute opacity of the actor, as it appears on the stage
10368  *
10369  * This function does not do type checks
10370  *
10371  * Return value: the absolute opacity of the actor
10372  */
10373 static guint8
10374 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10375 {
10376   ClutterActorPrivate *priv = self->priv;
10377   ClutterActor *parent;
10378
10379   /* override the top-level opacity to always be 255; even in
10380    * case of ClutterStage:use-alpha being TRUE we want the rest
10381    * of the scene to be painted
10382    */
10383   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10384     return 255;
10385
10386   if (priv->opacity_override >= 0)
10387     return priv->opacity_override;
10388
10389   parent = priv->parent;
10390
10391   /* Factor in the actual actors opacity with parents */
10392   if (parent != NULL)
10393     {
10394       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10395
10396       if (opacity != 0xff)
10397         return (opacity * priv->opacity) / 0xff;
10398     }
10399
10400   return priv->opacity;
10401
10402 }
10403
10404 /**
10405  * clutter_actor_get_paint_opacity:
10406  * @self: A #ClutterActor
10407  *
10408  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10409  *
10410  * This function traverses the hierarchy chain and composites the opacity of
10411  * the actor with that of its parents.
10412  *
10413  * This function is intended for subclasses to use in the paint virtual
10414  * function, to paint themselves with the correct opacity.
10415  *
10416  * Return value: The actor opacity value.
10417  *
10418  * Since: 0.8
10419  */
10420 guint8
10421 clutter_actor_get_paint_opacity (ClutterActor *self)
10422 {
10423   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10424
10425   return clutter_actor_get_paint_opacity_internal (self);
10426 }
10427
10428 /**
10429  * clutter_actor_get_opacity:
10430  * @self: a #ClutterActor
10431  *
10432  * Retrieves the opacity value of an actor, as set by
10433  * clutter_actor_set_opacity().
10434  *
10435  * For retrieving the absolute opacity of the actor inside a paint
10436  * virtual function, see clutter_actor_get_paint_opacity().
10437  *
10438  * Return value: the opacity of the actor
10439  */
10440 guint8
10441 clutter_actor_get_opacity (ClutterActor *self)
10442 {
10443   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10444
10445   return self->priv->opacity;
10446 }
10447
10448 /**
10449  * clutter_actor_set_offscreen_redirect:
10450  * @self: A #ClutterActor
10451  * @redirect: New offscreen redirect flags for the actor.
10452  *
10453  * Defines the circumstances where the actor should be redirected into
10454  * an offscreen image. The offscreen image is used to flatten the
10455  * actor into a single image while painting for two main reasons.
10456  * Firstly, when the actor is painted a second time without any of its
10457  * contents changing it can simply repaint the cached image without
10458  * descending further down the actor hierarchy. Secondly, it will make
10459  * the opacity look correct even if there are overlapping primitives
10460  * in the actor.
10461  *
10462  * Caching the actor could in some cases be a performance win and in
10463  * some cases be a performance lose so it is important to determine
10464  * which value is right for an actor before modifying this value. For
10465  * example, there is never any reason to flatten an actor that is just
10466  * a single texture (such as a #ClutterTexture) because it is
10467  * effectively already cached in an image so the offscreen would be
10468  * redundant. Also if the actor contains primitives that are far apart
10469  * with a large transparent area in the middle (such as a large
10470  * CluterGroup with a small actor in the top left and a small actor in
10471  * the bottom right) then the cached image will contain the entire
10472  * image of the large area and the paint will waste time blending all
10473  * of the transparent pixels in the middle.
10474  *
10475  * The default method of implementing opacity on a container simply
10476  * forwards on the opacity to all of the children. If the children are
10477  * overlapping then it will appear as if they are two separate glassy
10478  * objects and there will be a break in the color where they
10479  * overlap. By redirecting to an offscreen buffer it will be as if the
10480  * two opaque objects are combined into one and then made transparent
10481  * which is usually what is expected.
10482  *
10483  * The image below demonstrates the difference between redirecting and
10484  * not. The image shows two Clutter groups, each containing a red and
10485  * a green rectangle which overlap. The opacity on the group is set to
10486  * 128 (which is 50%). When the offscreen redirect is not used, the
10487  * red rectangle can be seen through the blue rectangle as if the two
10488  * rectangles were separately transparent. When the redirect is used
10489  * the group as a whole is transparent instead so the red rectangle is
10490  * not visible where they overlap.
10491  *
10492  * <figure id="offscreen-redirect">
10493  *   <title>Sample of using an offscreen redirect for transparency</title>
10494  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10495  * </figure>
10496  *
10497  * The default value for this property is 0, so we effectively will
10498  * never redirect an actor offscreen by default. This means that there
10499  * are times that transparent actors may look glassy as described
10500  * above. The reason this is the default is because there is a
10501  * performance trade off between quality and performance here. In many
10502  * cases the default form of glassy opacity looks good enough, but if
10503  * it's not you will need to set the
10504  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10505  * redirection for opacity.
10506  *
10507  * Custom actors that don't contain any overlapping primitives are
10508  * recommended to override the has_overlaps() virtual to return %FALSE
10509  * for maximum efficiency.
10510  *
10511  * Since: 1.8
10512  */
10513 void
10514 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10515                                       ClutterOffscreenRedirect redirect)
10516 {
10517   ClutterActorPrivate *priv;
10518
10519   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10520
10521   priv = self->priv;
10522
10523   if (priv->offscreen_redirect != redirect)
10524     {
10525       priv->offscreen_redirect = redirect;
10526
10527       /* Queue a redraw from the effect so that it can use its cached
10528          image if available instead of having to redraw the actual
10529          actor. If it doesn't end up using the FBO then the effect is
10530          still able to continue the paint anyway. If there is no
10531          effect then this is equivalent to queuing a full redraw */
10532       _clutter_actor_queue_redraw_full (self,
10533                                         0, /* flags */
10534                                         NULL, /* clip */
10535                                         priv->flatten_effect);
10536
10537       g_object_notify_by_pspec (G_OBJECT (self),
10538                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10539     }
10540 }
10541
10542 /**
10543  * clutter_actor_get_offscreen_redirect:
10544  * @self: a #ClutterActor
10545  *
10546  * Retrieves whether to redirect the actor to an offscreen buffer, as
10547  * set by clutter_actor_set_offscreen_redirect().
10548  *
10549  * Return value: the value of the offscreen-redirect property of the actor
10550  *
10551  * Since: 1.8
10552  */
10553 ClutterOffscreenRedirect
10554 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10555 {
10556   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10557
10558   return self->priv->offscreen_redirect;
10559 }
10560
10561 /**
10562  * clutter_actor_set_name:
10563  * @self: A #ClutterActor
10564  * @name: Textual tag to apply to actor
10565  *
10566  * Sets the given name to @self. The name can be used to identify
10567  * a #ClutterActor.
10568  */
10569 void
10570 clutter_actor_set_name (ClutterActor *self,
10571                         const gchar  *name)
10572 {
10573   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10574
10575   g_free (self->priv->name);
10576   self->priv->name = g_strdup (name);
10577
10578   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10579 }
10580
10581 /**
10582  * clutter_actor_get_name:
10583  * @self: A #ClutterActor
10584  *
10585  * Retrieves the name of @self.
10586  *
10587  * Return value: the name of the actor, or %NULL. The returned string is
10588  *   owned by the actor and should not be modified or freed.
10589  */
10590 const gchar *
10591 clutter_actor_get_name (ClutterActor *self)
10592 {
10593   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10594
10595   return self->priv->name;
10596 }
10597
10598 /**
10599  * clutter_actor_get_gid:
10600  * @self: A #ClutterActor
10601  *
10602  * Retrieves the unique id for @self.
10603  *
10604  * Return value: Globally unique value for this object instance.
10605  *
10606  * Since: 0.6
10607  *
10608  * Deprecated: 1.8: The id is not used any longer.
10609  */
10610 guint32
10611 clutter_actor_get_gid (ClutterActor *self)
10612 {
10613   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10614
10615   return self->priv->id;
10616 }
10617
10618 static inline void
10619 clutter_actor_set_depth_internal (ClutterActor *self,
10620                                   float         depth)
10621 {
10622   ClutterTransformInfo *info;
10623
10624   info = _clutter_actor_get_transform_info (self);
10625
10626   if (info->depth != depth)
10627     {
10628       /* Sets Z value - XXX 2.0: should we invert? */
10629       info->depth = depth;
10630
10631       self->priv->transform_valid = FALSE;
10632
10633       /* FIXME - remove this crap; sadly, there are still containers
10634        * in Clutter that depend on this utter brain damage
10635        */
10636       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10637
10638       clutter_actor_queue_redraw (self);
10639
10640       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10641     }
10642 }
10643
10644 /**
10645  * clutter_actor_set_depth:
10646  * @self: a #ClutterActor
10647  * @depth: Z co-ord
10648  *
10649  * Sets the Z coordinate of @self to @depth.
10650  *
10651  * The unit used by @depth is dependant on the perspective setup. See
10652  * also clutter_stage_set_perspective().
10653  */
10654 void
10655 clutter_actor_set_depth (ClutterActor *self,
10656                          gfloat        depth)
10657 {
10658   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10659
10660   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10661     {
10662       const ClutterTransformInfo *info;
10663
10664       info = _clutter_actor_get_transform_info_or_defaults (self);
10665
10666       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10667                                         info->depth,
10668                                         depth);
10669     }
10670   else
10671     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10672
10673   clutter_actor_queue_redraw (self);
10674 }
10675
10676 /**
10677  * clutter_actor_get_depth:
10678  * @self: a #ClutterActor
10679  *
10680  * Retrieves the depth of @self.
10681  *
10682  * Return value: the depth of the actor
10683  */
10684 gfloat
10685 clutter_actor_get_depth (ClutterActor *self)
10686 {
10687   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10688
10689   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10690 }
10691
10692 /**
10693  * clutter_actor_set_rotation:
10694  * @self: a #ClutterActor
10695  * @axis: the axis of rotation
10696  * @angle: the angle of rotation
10697  * @x: X coordinate of the rotation center
10698  * @y: Y coordinate of the rotation center
10699  * @z: Z coordinate of the rotation center
10700  *
10701  * Sets the rotation angle of @self around the given axis.
10702  *
10703  * The rotation center coordinates used depend on the value of @axis:
10704  * <itemizedlist>
10705  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10706  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10707  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10708  * </itemizedlist>
10709  *
10710  * The rotation coordinates are relative to the anchor point of the
10711  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10712  * point is set, the upper left corner is assumed as the origin.
10713  *
10714  * Since: 0.8
10715  */
10716 void
10717 clutter_actor_set_rotation (ClutterActor      *self,
10718                             ClutterRotateAxis  axis,
10719                             gdouble            angle,
10720                             gfloat             x,
10721                             gfloat             y,
10722                             gfloat             z)
10723 {
10724   ClutterVertex v;
10725
10726   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10727
10728   v.x = x;
10729   v.y = y;
10730   v.z = z;
10731
10732   g_object_freeze_notify (G_OBJECT (self));
10733
10734   clutter_actor_set_rotation_angle (self, axis, angle);
10735   clutter_actor_set_rotation_center_internal (self, axis, &v);
10736
10737   g_object_thaw_notify (G_OBJECT (self));
10738 }
10739
10740 /**
10741  * clutter_actor_set_z_rotation_from_gravity:
10742  * @self: a #ClutterActor
10743  * @angle: the angle of rotation
10744  * @gravity: the center point of the rotation
10745  *
10746  * Sets the rotation angle of @self around the Z axis using the center
10747  * point specified as a compass point. For example to rotate such that
10748  * the center of the actor remains static you can use
10749  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10750  * will move accordingly.
10751  *
10752  * Since: 1.0
10753  */
10754 void
10755 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10756                                            gdouble         angle,
10757                                            ClutterGravity  gravity)
10758 {
10759   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10760
10761   if (gravity == CLUTTER_GRAVITY_NONE)
10762     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10763   else
10764     {
10765       GObject *obj = G_OBJECT (self);
10766       ClutterTransformInfo *info;
10767
10768       info = _clutter_actor_get_transform_info (self);
10769
10770       g_object_freeze_notify (obj);
10771
10772       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10773
10774       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10775       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10776       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10777
10778       g_object_thaw_notify (obj);
10779     }
10780 }
10781
10782 /**
10783  * clutter_actor_get_rotation:
10784  * @self: a #ClutterActor
10785  * @axis: the axis of rotation
10786  * @x: (out): return value for the X coordinate of the center of rotation
10787  * @y: (out): return value for the Y coordinate of the center of rotation
10788  * @z: (out): return value for the Z coordinate of the center of rotation
10789  *
10790  * Retrieves the angle and center of rotation on the given axis,
10791  * set using clutter_actor_set_rotation().
10792  *
10793  * Return value: the angle of rotation
10794  *
10795  * Since: 0.8
10796  */
10797 gdouble
10798 clutter_actor_get_rotation (ClutterActor      *self,
10799                             ClutterRotateAxis  axis,
10800                             gfloat            *x,
10801                             gfloat            *y,
10802                             gfloat            *z)
10803 {
10804   const ClutterTransformInfo *info;
10805   const AnchorCoord *anchor_coord;
10806   gdouble retval = 0;
10807
10808   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10809
10810   info = _clutter_actor_get_transform_info_or_defaults (self);
10811
10812   switch (axis)
10813     {
10814     case CLUTTER_X_AXIS:
10815       anchor_coord = &info->rx_center;
10816       retval = info->rx_angle;
10817       break;
10818
10819     case CLUTTER_Y_AXIS:
10820       anchor_coord = &info->ry_center;
10821       retval = info->ry_angle;
10822       break;
10823
10824     case CLUTTER_Z_AXIS:
10825       anchor_coord = &info->rz_center;
10826       retval = info->rz_angle;
10827       break;
10828
10829     default:
10830       anchor_coord = NULL;
10831       retval = 0.0;
10832       break;
10833     }
10834
10835   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10836
10837   return retval;
10838 }
10839
10840 /**
10841  * clutter_actor_get_z_rotation_gravity:
10842  * @self: A #ClutterActor
10843  *
10844  * Retrieves the center for the rotation around the Z axis as a
10845  * compass direction. If the center was specified in pixels or units
10846  * this will return %CLUTTER_GRAVITY_NONE.
10847  *
10848  * Return value: the Z rotation center
10849  *
10850  * Since: 1.0
10851  */
10852 ClutterGravity
10853 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10854 {
10855   const ClutterTransformInfo *info;
10856
10857   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10858
10859   info = _clutter_actor_get_transform_info_or_defaults (self);
10860
10861   return clutter_anchor_coord_get_gravity (&info->rz_center);
10862 }
10863
10864 /**
10865  * clutter_actor_set_clip:
10866  * @self: A #ClutterActor
10867  * @xoff: X offset of the clip rectangle
10868  * @yoff: Y offset of the clip rectangle
10869  * @width: Width of the clip rectangle
10870  * @height: Height of the clip rectangle
10871  *
10872  * Sets clip area for @self. The clip area is always computed from the
10873  * upper left corner of the actor, even if the anchor point is set
10874  * otherwise.
10875  *
10876  * Since: 0.6
10877  */
10878 void
10879 clutter_actor_set_clip (ClutterActor *self,
10880                         gfloat        xoff,
10881                         gfloat        yoff,
10882                         gfloat        width,
10883                         gfloat        height)
10884 {
10885   ClutterActorPrivate *priv;
10886
10887   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10888
10889   priv = self->priv;
10890
10891   if (priv->has_clip &&
10892       priv->clip.x == xoff &&
10893       priv->clip.y == yoff &&
10894       priv->clip.width == width &&
10895       priv->clip.height == height)
10896     return;
10897
10898   priv->clip.x = xoff;
10899   priv->clip.y = yoff;
10900   priv->clip.width = width;
10901   priv->clip.height = height;
10902
10903   priv->has_clip = TRUE;
10904
10905   clutter_actor_queue_redraw (self);
10906
10907   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10908   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10909 }
10910
10911 /**
10912  * clutter_actor_remove_clip:
10913  * @self: A #ClutterActor
10914  *
10915  * Removes clip area from @self.
10916  */
10917 void
10918 clutter_actor_remove_clip (ClutterActor *self)
10919 {
10920   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10921
10922   if (!self->priv->has_clip)
10923     return;
10924
10925   self->priv->has_clip = FALSE;
10926
10927   clutter_actor_queue_redraw (self);
10928
10929   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10930 }
10931
10932 /**
10933  * clutter_actor_has_clip:
10934  * @self: a #ClutterActor
10935  *
10936  * Determines whether the actor has a clip area set or not.
10937  *
10938  * Return value: %TRUE if the actor has a clip area set.
10939  *
10940  * Since: 0.1.1
10941  */
10942 gboolean
10943 clutter_actor_has_clip (ClutterActor *self)
10944 {
10945   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10946
10947   return self->priv->has_clip;
10948 }
10949
10950 /**
10951  * clutter_actor_get_clip:
10952  * @self: a #ClutterActor
10953  * @xoff: (out) (allow-none): return location for the X offset of
10954  *   the clip rectangle, or %NULL
10955  * @yoff: (out) (allow-none): return location for the Y offset of
10956  *   the clip rectangle, or %NULL
10957  * @width: (out) (allow-none): return location for the width of
10958  *   the clip rectangle, or %NULL
10959  * @height: (out) (allow-none): return location for the height of
10960  *   the clip rectangle, or %NULL
10961  *
10962  * Gets the clip area for @self, if any is set
10963  *
10964  * Since: 0.6
10965  */
10966 void
10967 clutter_actor_get_clip (ClutterActor *self,
10968                         gfloat       *xoff,
10969                         gfloat       *yoff,
10970                         gfloat       *width,
10971                         gfloat       *height)
10972 {
10973   ClutterActorPrivate *priv;
10974
10975   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10976
10977   priv = self->priv;
10978
10979   if (!priv->has_clip)
10980     return;
10981
10982   if (xoff != NULL)
10983     *xoff = priv->clip.x;
10984
10985   if (yoff != NULL)
10986     *yoff = priv->clip.y;
10987
10988   if (width != NULL)
10989     *width = priv->clip.width;
10990
10991   if (height != NULL)
10992     *height = priv->clip.height;
10993 }
10994
10995 /**
10996  * clutter_actor_get_children:
10997  * @self: a #ClutterActor
10998  *
10999  * Retrieves the list of children of @self.
11000  *
11001  * Return value: (transfer container) (element-type ClutterActor): A newly
11002  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
11003  *   done.
11004  *
11005  * Since: 1.10
11006  */
11007 GList *
11008 clutter_actor_get_children (ClutterActor *self)
11009 {
11010   ClutterActor *iter;
11011   GList *res;
11012
11013   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11014
11015   /* we walk the list backward so that we can use prepend(),
11016    * which is O(1)
11017    */
11018   for (iter = self->priv->last_child, res = NULL;
11019        iter != NULL;
11020        iter = iter->priv->prev_sibling)
11021     {
11022       res = g_list_prepend (res, iter);
11023     }
11024
11025   return res;
11026 }
11027
11028 /*< private >
11029  * insert_child_at_depth:
11030  * @self: a #ClutterActor
11031  * @child: a #ClutterActor
11032  *
11033  * Inserts @child inside the list of children held by @self, using
11034  * the depth as the insertion criteria.
11035  *
11036  * This sadly makes the insertion not O(1), but we can keep the
11037  * list sorted so that the painters algorithm we use for painting
11038  * the children will work correctly.
11039  */
11040 static void
11041 insert_child_at_depth (ClutterActor *self,
11042                        ClutterActor *child,
11043                        gpointer      dummy G_GNUC_UNUSED)
11044 {
11045   ClutterActor *iter;
11046   float child_depth;
11047
11048   child->priv->parent = self;
11049
11050   child_depth =
11051     _clutter_actor_get_transform_info_or_defaults (child)->depth;
11052
11053   /* special-case the first child */
11054   if (self->priv->n_children == 0)
11055     {
11056       self->priv->first_child = child;
11057       self->priv->last_child = child;
11058
11059       child->priv->next_sibling = NULL;
11060       child->priv->prev_sibling = NULL;
11061
11062       return;
11063     }
11064
11065   /* Find the right place to insert the child so that it will still be
11066      sorted and the child will be after all of the actors at the same
11067      dept */
11068   for (iter = self->priv->first_child;
11069        iter != NULL;
11070        iter = iter->priv->next_sibling)
11071     {
11072       float iter_depth;
11073
11074       iter_depth =
11075         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
11076
11077       if (iter_depth > child_depth)
11078         break;
11079     }
11080
11081   if (iter != NULL)
11082     {
11083       ClutterActor *tmp = iter->priv->prev_sibling;
11084
11085       if (tmp != NULL)
11086         tmp->priv->next_sibling = child;
11087
11088       /* Insert the node before the found one */
11089       child->priv->prev_sibling = iter->priv->prev_sibling;
11090       child->priv->next_sibling = iter;
11091       iter->priv->prev_sibling = child;
11092     }
11093   else
11094     {
11095       ClutterActor *tmp = self->priv->last_child;
11096
11097       if (tmp != NULL)
11098         tmp->priv->next_sibling = child;
11099
11100       /* insert the node at the end of the list */
11101       child->priv->prev_sibling = self->priv->last_child;
11102       child->priv->next_sibling = NULL;
11103     }
11104
11105   if (child->priv->prev_sibling == NULL)
11106     self->priv->first_child = child;
11107
11108   if (child->priv->next_sibling == NULL)
11109     self->priv->last_child = child;
11110 }
11111
11112 static void
11113 insert_child_at_index (ClutterActor *self,
11114                        ClutterActor *child,
11115                        gpointer      data_)
11116 {
11117   gint index_ = GPOINTER_TO_INT (data_);
11118
11119   child->priv->parent = self;
11120
11121   if (index_ == 0)
11122     {
11123       ClutterActor *tmp = self->priv->first_child;
11124
11125       if (tmp != NULL)
11126         tmp->priv->prev_sibling = child;
11127
11128       child->priv->prev_sibling = NULL;
11129       child->priv->next_sibling = tmp;
11130     }
11131   else if (index_ < 0 || index_ >= self->priv->n_children)
11132     {
11133       ClutterActor *tmp = self->priv->last_child;
11134
11135       if (tmp != NULL)
11136         tmp->priv->next_sibling = child;
11137
11138       child->priv->prev_sibling = tmp;
11139       child->priv->next_sibling = NULL;
11140     }
11141   else
11142     {
11143       ClutterActor *iter;
11144       int i;
11145
11146       for (iter = self->priv->first_child, i = 0;
11147            iter != NULL;
11148            iter = iter->priv->next_sibling, i += 1)
11149         {
11150           if (index_ == i)
11151             {
11152               ClutterActor *tmp = iter->priv->prev_sibling;
11153
11154               child->priv->prev_sibling = tmp;
11155               child->priv->next_sibling = iter;
11156
11157               iter->priv->prev_sibling = child;
11158
11159               if (tmp != NULL)
11160                 tmp->priv->next_sibling = child;
11161
11162               break;
11163             }
11164         }
11165     }
11166
11167   if (child->priv->prev_sibling == NULL)
11168     self->priv->first_child = child;
11169
11170   if (child->priv->next_sibling == NULL)
11171     self->priv->last_child = child;
11172 }
11173
11174 static void
11175 insert_child_above (ClutterActor *self,
11176                     ClutterActor *child,
11177                     gpointer      data)
11178 {
11179   ClutterActor *sibling = data;
11180
11181   child->priv->parent = self;
11182
11183   if (sibling == NULL)
11184     sibling = self->priv->last_child;
11185
11186   child->priv->prev_sibling = sibling;
11187
11188   if (sibling != NULL)
11189     {
11190       ClutterActor *tmp = sibling->priv->next_sibling;
11191
11192       child->priv->next_sibling = tmp;
11193
11194       if (tmp != NULL)
11195         tmp->priv->prev_sibling = child;
11196
11197       sibling->priv->next_sibling = child;
11198     }
11199   else
11200     child->priv->next_sibling = NULL;
11201
11202   if (child->priv->prev_sibling == NULL)
11203     self->priv->first_child = child;
11204
11205   if (child->priv->next_sibling == NULL)
11206     self->priv->last_child = child;
11207 }
11208
11209 static void
11210 insert_child_below (ClutterActor *self,
11211                     ClutterActor *child,
11212                     gpointer      data)
11213 {
11214   ClutterActor *sibling = data;
11215
11216   child->priv->parent = self;
11217
11218   if (sibling == NULL)
11219     sibling = self->priv->first_child;
11220
11221   child->priv->next_sibling = sibling;
11222
11223   if (sibling != NULL)
11224     {
11225       ClutterActor *tmp = sibling->priv->prev_sibling;
11226
11227       child->priv->prev_sibling = tmp;
11228
11229       if (tmp != NULL)
11230         tmp->priv->next_sibling = child;
11231
11232       sibling->priv->prev_sibling = child;
11233     }
11234   else
11235     child->priv->prev_sibling = NULL;
11236
11237   if (child->priv->prev_sibling == NULL)
11238     self->priv->first_child = child;
11239
11240   if (child->priv->next_sibling == NULL)
11241     self->priv->last_child = child;
11242 }
11243
11244 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11245                                            ClutterActor *child,
11246                                            gpointer      data);
11247
11248 typedef enum {
11249   ADD_CHILD_CREATE_META        = 1 << 0,
11250   ADD_CHILD_EMIT_PARENT_SET    = 1 << 1,
11251   ADD_CHILD_EMIT_ACTOR_ADDED   = 1 << 2,
11252   ADD_CHILD_CHECK_STATE        = 1 << 3,
11253   ADD_CHILD_NOTIFY_FIRST_LAST  = 1 << 4,
11254   ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11255
11256   /* default flags for public API */
11257   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
11258                                ADD_CHILD_EMIT_PARENT_SET |
11259                                ADD_CHILD_EMIT_ACTOR_ADDED |
11260                                ADD_CHILD_CHECK_STATE |
11261                                ADD_CHILD_NOTIFY_FIRST_LAST |
11262                                ADD_CHILD_SHOW_ON_SET_PARENT,
11263
11264   /* flags for legacy/deprecated API */
11265   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
11266                                ADD_CHILD_CHECK_STATE |
11267                                ADD_CHILD_NOTIFY_FIRST_LAST |
11268                                ADD_CHILD_SHOW_ON_SET_PARENT
11269 } ClutterActorAddChildFlags;
11270
11271 /*< private >
11272  * clutter_actor_add_child_internal:
11273  * @self: a #ClutterActor
11274  * @child: a #ClutterActor
11275  * @flags: control flags for actions
11276  * @add_func: delegate function
11277  * @data: (closure): data to pass to @add_func
11278  *
11279  * Adds @child to the list of children of @self.
11280  *
11281  * The actual insertion inside the list is delegated to @add_func: this
11282  * function will just set up the state, perform basic checks, and emit
11283  * signals.
11284  *
11285  * The @flags argument is used to perform additional operations.
11286  */
11287 static inline void
11288 clutter_actor_add_child_internal (ClutterActor              *self,
11289                                   ClutterActor              *child,
11290                                   ClutterActorAddChildFlags  flags,
11291                                   ClutterActorAddChildFunc   add_func,
11292                                   gpointer                   data)
11293 {
11294   ClutterTextDirection text_dir;
11295   gboolean create_meta;
11296   gboolean emit_parent_set, emit_actor_added;
11297   gboolean check_state;
11298   gboolean notify_first_last;
11299   gboolean show_on_set_parent;
11300   ClutterActor *old_first_child, *old_last_child;
11301
11302   if (child->priv->parent != NULL)
11303     {
11304       g_warning ("The actor '%s' already has a parent, '%s'. You must "
11305                  "use clutter_actor_remove_child() first.",
11306                  _clutter_actor_get_debug_name (child),
11307                  _clutter_actor_get_debug_name (child->priv->parent));
11308       return;
11309     }
11310
11311   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11312     {
11313       g_warning ("The actor '%s' is a top-level actor, and cannot be "
11314                  "a child of another actor.",
11315                  _clutter_actor_get_debug_name (child));
11316       return;
11317     }
11318
11319 #if 0
11320   /* XXX - this check disallows calling methods that change the stacking
11321    * order within the destruction sequence, by triggering a critical
11322    * warning first, and leaving the actor in an undefined state, which
11323    * then ends up being caught by an assertion.
11324    *
11325    * the reproducible sequence is:
11326    *
11327    *   - actor gets destroyed;
11328    *   - another actor, linked to the first, will try to change the
11329    *     stacking order of the first actor;
11330    *   - changing the stacking order is a composite operation composed
11331    *     by the following steps:
11332    *     1. ref() the child;
11333    *     2. remove_child_internal(), which removes the reference;
11334    *     3. add_child_internal(), which adds a reference;
11335    *   - the state of the actor is not changed between (2) and (3), as
11336    *     it could be an expensive recomputation;
11337    *   - if (3) bails out, then the actor is in an undefined state, but
11338    *     still alive;
11339    *   - the destruction sequence terminates, but the actor is unparented
11340    *     while its state indicates being parented instead.
11341    *   - assertion failure.
11342    *
11343    * the obvious fix would be to decompose each set_child_*_sibling()
11344    * method into proper remove_child()/add_child(), with state validation;
11345    * this may cause excessive work, though, and trigger a cascade of other
11346    * bugs in code that assumes that a change in the stacking order is an
11347    * atomic operation.
11348    *
11349    * another potential fix is to just remove this check here, and let
11350    * code doing stacking order changes inside the destruction sequence
11351    * of an actor continue doing the work.
11352    *
11353    * the third fix is to silently bail out early from every
11354    * set_child_*_sibling() and set_child_at_index() method, and avoid
11355    * doing work.
11356    *
11357    * I have a preference for the second solution, since it involves the
11358    * least amount of work, and the least amount of code duplication.
11359    *
11360    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11361    */
11362   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11363     {
11364       g_warning ("The actor '%s' is currently being destroyed, and "
11365                  "cannot be added as a child of another actor.",
11366                  _clutter_actor_get_debug_name (child));
11367       return;
11368     }
11369 #endif
11370
11371   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11372   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11373   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11374   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11375   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11376   show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11377
11378   old_first_child = self->priv->first_child;
11379   old_last_child = self->priv->last_child;
11380
11381   g_object_freeze_notify (G_OBJECT (self));
11382
11383   if (create_meta)
11384     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11385
11386   g_object_ref_sink (child);
11387   child->priv->parent = NULL;
11388   child->priv->next_sibling = NULL;
11389   child->priv->prev_sibling = NULL;
11390
11391   /* delegate the actual insertion */
11392   add_func (self, child, data);
11393
11394   g_assert (child->priv->parent == self);
11395
11396   self->priv->n_children += 1;
11397
11398   self->priv->age += 1;
11399
11400   /* if push_internal() has been called then we automatically set
11401    * the flag on the actor
11402    */
11403   if (self->priv->internal_child)
11404     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11405
11406   /* children may cause their parent to expand, if they are set
11407    * to expand; if a child is not expanded then it cannot change
11408    * its parent's state. any further change later on will queue
11409    * an expand state check.
11410    *
11411    * this check, with the initial state of the needs_compute_expand
11412    * flag set to FALSE, should avoid recomputing the expand flags
11413    * state while building the actor tree.
11414    */
11415   if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
11416       (child->priv->needs_compute_expand ||
11417        child->priv->needs_x_expand ||
11418        child->priv->needs_y_expand))
11419     {
11420       clutter_actor_queue_compute_expand (self);
11421     }
11422
11423   /* clutter_actor_reparent() will emit ::parent-set for us */
11424   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11425     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11426
11427   if (check_state)
11428     {
11429       /* If parent is mapped or realized, we need to also be mapped or
11430        * realized once we're inside the parent.
11431        */
11432       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11433
11434       /* propagate the parent's text direction to the child */
11435       text_dir = clutter_actor_get_text_direction (self);
11436       clutter_actor_set_text_direction (child, text_dir);
11437     }
11438
11439   if (show_on_set_parent && child->priv->show_on_set_parent)
11440     clutter_actor_show (child);
11441
11442   if (CLUTTER_ACTOR_IS_MAPPED (child))
11443     clutter_actor_queue_redraw (child);
11444
11445   /* maintain the invariant that if an actor needs layout,
11446    * its parents do as well
11447    */
11448   if (child->priv->needs_width_request ||
11449       child->priv->needs_height_request ||
11450       child->priv->needs_allocation)
11451     {
11452       /* we work around the short-circuiting we do
11453        * in clutter_actor_queue_relayout() since we
11454        * want to force a relayout
11455        */
11456       child->priv->needs_width_request = TRUE;
11457       child->priv->needs_height_request = TRUE;
11458       child->priv->needs_allocation = TRUE;
11459
11460       clutter_actor_queue_relayout (child->priv->parent);
11461     }
11462
11463   if (emit_actor_added)
11464     g_signal_emit_by_name (self, "actor-added", child);
11465
11466   if (notify_first_last)
11467     {
11468       if (old_first_child != self->priv->first_child)
11469         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11470
11471       if (old_last_child != self->priv->last_child)
11472         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11473     }
11474
11475   g_object_thaw_notify (G_OBJECT (self));
11476 }
11477
11478 /**
11479  * clutter_actor_add_child:
11480  * @self: a #ClutterActor
11481  * @child: a #ClutterActor
11482  *
11483  * Adds @child to the children of @self.
11484  *
11485  * This function will acquire a reference on @child that will only
11486  * be released when calling clutter_actor_remove_child().
11487  *
11488  * This function will take into consideration the #ClutterActor:depth
11489  * of @child, and will keep the list of children sorted.
11490  *
11491  * This function will emit the #ClutterContainer::actor-added signal
11492  * on @self.
11493  *
11494  * Since: 1.10
11495  */
11496 void
11497 clutter_actor_add_child (ClutterActor *self,
11498                          ClutterActor *child)
11499 {
11500   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11501   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11502   g_return_if_fail (self != child);
11503   g_return_if_fail (child->priv->parent == NULL);
11504
11505   clutter_actor_add_child_internal (self, child,
11506                                     ADD_CHILD_DEFAULT_FLAGS,
11507                                     insert_child_at_depth,
11508                                     NULL);
11509 }
11510
11511 /**
11512  * clutter_actor_insert_child_at_index:
11513  * @self: a #ClutterActor
11514  * @child: a #ClutterActor
11515  * @index_: the index
11516  *
11517  * Inserts @child into the list of children of @self, using the
11518  * given @index_. If @index_ is greater than the number of children
11519  * in @self, or is less than 0, then the new child is added at the end.
11520  *
11521  * This function will acquire a reference on @child that will only
11522  * be released when calling clutter_actor_remove_child().
11523  *
11524  * This function will not take into consideration the #ClutterActor:depth
11525  * of @child.
11526  *
11527  * This function will emit the #ClutterContainer::actor-added signal
11528  * on @self.
11529  *
11530  * Since: 1.10
11531  */
11532 void
11533 clutter_actor_insert_child_at_index (ClutterActor *self,
11534                                      ClutterActor *child,
11535                                      gint          index_)
11536 {
11537   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11538   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11539   g_return_if_fail (self != child);
11540   g_return_if_fail (child->priv->parent == NULL);
11541
11542   clutter_actor_add_child_internal (self, child,
11543                                     ADD_CHILD_DEFAULT_FLAGS,
11544                                     insert_child_at_index,
11545                                     GINT_TO_POINTER (index_));
11546 }
11547
11548 /**
11549  * clutter_actor_insert_child_above:
11550  * @self: a #ClutterActor
11551  * @child: a #ClutterActor
11552  * @sibling: (allow-none): a child of @self, or %NULL
11553  *
11554  * Inserts @child into the list of children of @self, above another
11555  * child of @self or, if @sibling is %NULL, above all the children
11556  * of @self.
11557  *
11558  * This function will acquire a reference on @child that will only
11559  * be released when calling clutter_actor_remove_child().
11560  *
11561  * This function will not take into consideration the #ClutterActor:depth
11562  * of @child.
11563  *
11564  * This function will emit the #ClutterContainer::actor-added signal
11565  * on @self.
11566  *
11567  * Since: 1.10
11568  */
11569 void
11570 clutter_actor_insert_child_above (ClutterActor *self,
11571                                   ClutterActor *child,
11572                                   ClutterActor *sibling)
11573 {
11574   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11575   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11576   g_return_if_fail (self != child);
11577   g_return_if_fail (child != sibling);
11578   g_return_if_fail (child->priv->parent == NULL);
11579   g_return_if_fail (sibling == NULL ||
11580                     (CLUTTER_IS_ACTOR (sibling) &&
11581                      sibling->priv->parent == self));
11582
11583   clutter_actor_add_child_internal (self, child,
11584                                     ADD_CHILD_DEFAULT_FLAGS,
11585                                     insert_child_above,
11586                                     sibling);
11587 }
11588
11589 /**
11590  * clutter_actor_insert_child_below:
11591  * @self: a #ClutterActor
11592  * @child: a #ClutterActor
11593  * @sibling: (allow-none): a child of @self, or %NULL
11594  *
11595  * Inserts @child into the list of children of @self, below another
11596  * child of @self or, if @sibling is %NULL, below all the children
11597  * of @self.
11598  *
11599  * This function will acquire a reference on @child that will only
11600  * be released when calling clutter_actor_remove_child().
11601  *
11602  * This function will not take into consideration the #ClutterActor:depth
11603  * of @child.
11604  *
11605  * This function will emit the #ClutterContainer::actor-added signal
11606  * on @self.
11607  *
11608  * Since: 1.10
11609  */
11610 void
11611 clutter_actor_insert_child_below (ClutterActor *self,
11612                                   ClutterActor *child,
11613                                   ClutterActor *sibling)
11614 {
11615   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11616   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11617   g_return_if_fail (self != child);
11618   g_return_if_fail (child != sibling);
11619   g_return_if_fail (child->priv->parent == NULL);
11620   g_return_if_fail (sibling == NULL ||
11621                     (CLUTTER_IS_ACTOR (sibling) &&
11622                      sibling->priv->parent == self));
11623
11624   clutter_actor_add_child_internal (self, child,
11625                                     ADD_CHILD_DEFAULT_FLAGS,
11626                                     insert_child_below,
11627                                     sibling);
11628 }
11629
11630 /**
11631  * clutter_actor_set_parent:
11632  * @self: A #ClutterActor
11633  * @parent: A new #ClutterActor parent
11634  *
11635  * Sets the parent of @self to @parent.
11636  *
11637  * This function will result in @parent acquiring a reference on @self,
11638  * eventually by sinking its floating reference first. The reference
11639  * will be released by clutter_actor_unparent().
11640  *
11641  * This function should only be called by legacy #ClutterActor<!-- -->s
11642  * implementing the #ClutterContainer interface.
11643  *
11644  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11645  */
11646 void
11647 clutter_actor_set_parent (ClutterActor *self,
11648                           ClutterActor *parent)
11649 {
11650   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11651   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11652   g_return_if_fail (self != parent);
11653   g_return_if_fail (self->priv->parent == NULL);
11654
11655   /* as this function will be called inside ClutterContainer::add
11656    * implementations or when building up a composite actor, we have
11657    * to preserve the old behaviour, and not create child meta or
11658    * emit the ::actor-added signal, to avoid recursion or double
11659    * emissions
11660    */
11661   clutter_actor_add_child_internal (parent, self,
11662                                     ADD_CHILD_LEGACY_FLAGS,
11663                                     insert_child_at_depth,
11664                                     NULL);
11665 }
11666
11667 /**
11668  * clutter_actor_get_parent:
11669  * @self: A #ClutterActor
11670  *
11671  * Retrieves the parent of @self.
11672  *
11673  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11674  *  if no parent is set
11675  */
11676 ClutterActor *
11677 clutter_actor_get_parent (ClutterActor *self)
11678 {
11679   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11680
11681   return self->priv->parent;
11682 }
11683
11684 /**
11685  * clutter_actor_get_paint_visibility:
11686  * @self: A #ClutterActor
11687  *
11688  * Retrieves the 'paint' visibility of an actor recursively checking for non
11689  * visible parents.
11690  *
11691  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11692  *
11693  * Return Value: %TRUE if the actor is visibile and will be painted.
11694  *
11695  * Since: 0.8.4
11696  */
11697 gboolean
11698 clutter_actor_get_paint_visibility (ClutterActor *actor)
11699 {
11700   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11701
11702   return CLUTTER_ACTOR_IS_MAPPED (actor);
11703 }
11704
11705 /**
11706  * clutter_actor_remove_child:
11707  * @self: a #ClutterActor
11708  * @child: a #ClutterActor
11709  *
11710  * Removes @child from the children of @self.
11711  *
11712  * This function will release the reference added by
11713  * clutter_actor_add_child(), so if you want to keep using @child
11714  * you will have to acquire a referenced on it before calling this
11715  * function.
11716  *
11717  * This function will emit the #ClutterContainer::actor-removed
11718  * signal on @self.
11719  *
11720  * Since: 1.10
11721  */
11722 void
11723 clutter_actor_remove_child (ClutterActor *self,
11724                             ClutterActor *child)
11725 {
11726   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11727   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11728   g_return_if_fail (self != child);
11729   g_return_if_fail (child->priv->parent != NULL);
11730   g_return_if_fail (child->priv->parent == self);
11731
11732   clutter_actor_remove_child_internal (self, child,
11733                                        REMOVE_CHILD_DEFAULT_FLAGS);
11734 }
11735
11736 /**
11737  * clutter_actor_remove_all_children:
11738  * @self: a #ClutterActor
11739  *
11740  * Removes all children of @self.
11741  *
11742  * This function releases the reference added by inserting a child actor
11743  * in the list of children of @self.
11744  *
11745  * If the reference count of a child drops to zero, the child will be
11746  * destroyed. If you want to ensure the destruction of all the children
11747  * of @self, use clutter_actor_destroy_all_children().
11748  *
11749  * Since: 1.10
11750  */
11751 void
11752 clutter_actor_remove_all_children (ClutterActor *self)
11753 {
11754   ClutterActorIter iter;
11755
11756   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11757
11758   if (self->priv->n_children == 0)
11759     return;
11760
11761   g_object_freeze_notify (G_OBJECT (self));
11762
11763   clutter_actor_iter_init (&iter, self);
11764   while (clutter_actor_iter_next (&iter, NULL))
11765     clutter_actor_iter_remove (&iter);
11766
11767   g_object_thaw_notify (G_OBJECT (self));
11768
11769   /* sanity check */
11770   g_assert (self->priv->first_child == NULL);
11771   g_assert (self->priv->last_child == NULL);
11772   g_assert (self->priv->n_children == 0);
11773 }
11774
11775 /**
11776  * clutter_actor_destroy_all_children:
11777  * @self: a #ClutterActor
11778  *
11779  * Destroys all children of @self.
11780  *
11781  * This function releases the reference added by inserting a child
11782  * actor in the list of children of @self, and ensures that the
11783  * #ClutterActor::destroy signal is emitted on each child of the
11784  * actor.
11785  *
11786  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11787  * when its reference count drops to 0; the default handler of the
11788  * #ClutterActor::destroy signal will destroy all the children of an
11789  * actor. This function ensures that all children are destroyed, instead
11790  * of just removed from @self, unlike clutter_actor_remove_all_children()
11791  * which will merely release the reference and remove each child.
11792  *
11793  * Unless you acquired an additional reference on each child of @self
11794  * prior to calling clutter_actor_remove_all_children() and want to reuse
11795  * the actors, you should use clutter_actor_destroy_all_children() in
11796  * order to make sure that children are destroyed and signal handlers
11797  * are disconnected even in cases where circular references prevent this
11798  * from automatically happening through reference counting alone.
11799  *
11800  * Since: 1.10
11801  */
11802 void
11803 clutter_actor_destroy_all_children (ClutterActor *self)
11804 {
11805   ClutterActorIter iter;
11806
11807   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11808
11809   if (self->priv->n_children == 0)
11810     return;
11811
11812   g_object_freeze_notify (G_OBJECT (self));
11813
11814   clutter_actor_iter_init (&iter, self);
11815   while (clutter_actor_iter_next (&iter, NULL))
11816     clutter_actor_iter_destroy (&iter);
11817
11818   g_object_thaw_notify (G_OBJECT (self));
11819
11820   /* sanity check */
11821   g_assert (self->priv->first_child == NULL);
11822   g_assert (self->priv->last_child == NULL);
11823   g_assert (self->priv->n_children == 0);
11824 }
11825
11826 typedef struct _InsertBetweenData {
11827   ClutterActor *prev_sibling;
11828   ClutterActor *next_sibling;
11829 } InsertBetweenData;
11830
11831 static void
11832 insert_child_between (ClutterActor *self,
11833                       ClutterActor *child,
11834                       gpointer      data_)
11835 {
11836   InsertBetweenData *data = data_;
11837   ClutterActor *prev_sibling = data->prev_sibling;
11838   ClutterActor *next_sibling = data->next_sibling;
11839
11840   child->priv->parent = self;
11841   child->priv->prev_sibling = prev_sibling;
11842   child->priv->next_sibling = next_sibling;
11843
11844   if (prev_sibling != NULL)
11845     prev_sibling->priv->next_sibling = child;
11846
11847   if (next_sibling != NULL)
11848     next_sibling->priv->prev_sibling = child;
11849
11850   if (child->priv->prev_sibling == NULL)
11851     self->priv->first_child = child;
11852
11853   if (child->priv->next_sibling == NULL)
11854     self->priv->last_child = child;
11855 }
11856
11857 /**
11858  * clutter_actor_replace_child:
11859  * @self: a #ClutterActor
11860  * @old_child: the child of @self to replace
11861  * @new_child: the #ClutterActor to replace @old_child
11862  *
11863  * Replaces @old_child with @new_child in the list of children of @self.
11864  *
11865  * Since: 1.10
11866  */
11867 void
11868 clutter_actor_replace_child (ClutterActor *self,
11869                              ClutterActor *old_child,
11870                              ClutterActor *new_child)
11871 {
11872   ClutterActor *prev_sibling, *next_sibling;
11873   InsertBetweenData clos;
11874
11875   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11876   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11877   g_return_if_fail (old_child->priv->parent == self);
11878   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11879   g_return_if_fail (old_child != new_child);
11880   g_return_if_fail (new_child != self);
11881   g_return_if_fail (new_child->priv->parent == NULL);
11882
11883   prev_sibling = old_child->priv->prev_sibling;
11884   next_sibling = old_child->priv->next_sibling;
11885   clutter_actor_remove_child_internal (self, old_child,
11886                                        REMOVE_CHILD_DEFAULT_FLAGS);
11887
11888   clos.prev_sibling = prev_sibling;
11889   clos.next_sibling = next_sibling;
11890   clutter_actor_add_child_internal (self, new_child,
11891                                     ADD_CHILD_DEFAULT_FLAGS,
11892                                     insert_child_between,
11893                                     &clos);
11894 }
11895
11896 /**
11897  * clutter_actor_unparent:
11898  * @self: a #ClutterActor
11899  *
11900  * Removes the parent of @self.
11901  *
11902  * This will cause the parent of @self to release the reference
11903  * acquired when calling clutter_actor_set_parent(), so if you
11904  * want to keep @self you will have to acquire a reference of
11905  * your own, through g_object_ref().
11906  *
11907  * This function should only be called by legacy #ClutterActor<!-- -->s
11908  * implementing the #ClutterContainer interface.
11909  *
11910  * Since: 0.1.1
11911  *
11912  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11913  */
11914 void
11915 clutter_actor_unparent (ClutterActor *self)
11916 {
11917   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11918
11919   if (self->priv->parent == NULL)
11920     return;
11921
11922   clutter_actor_remove_child_internal (self->priv->parent, self,
11923                                        REMOVE_CHILD_LEGACY_FLAGS);
11924 }
11925
11926 /**
11927  * clutter_actor_reparent:
11928  * @self: a #ClutterActor
11929  * @new_parent: the new #ClutterActor parent
11930  *
11931  * Resets the parent actor of @self.
11932  *
11933  * This function is logically equivalent to calling clutter_actor_unparent()
11934  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11935  * ensures the child is not finalized when unparented, and emits the
11936  * #ClutterActor::parent-set signal only once.
11937  *
11938  * In reality, calling this function is less useful than it sounds, as some
11939  * application code may rely on changes in the intermediate state between
11940  * removal and addition of the actor from its old parent to the @new_parent.
11941  * Thus, it is strongly encouraged to avoid using this function in application
11942  * code.
11943  *
11944  * Since: 0.2
11945  *
11946  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11947  *   clutter_actor_add_child() instead; remember to take a reference on
11948  *   the actor being removed before calling clutter_actor_remove_child()
11949  *   to avoid the reference count dropping to zero and the actor being
11950  *   destroyed.
11951  */
11952 void
11953 clutter_actor_reparent (ClutterActor *self,
11954                         ClutterActor *new_parent)
11955 {
11956   ClutterActorPrivate *priv;
11957
11958   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11959   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11960   g_return_if_fail (self != new_parent);
11961
11962   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11963     {
11964       g_warning ("Cannot set a parent on a toplevel actor");
11965       return;
11966     }
11967
11968   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11969     {
11970       g_warning ("Cannot set a parent currently being destroyed");
11971       return;
11972     }
11973
11974   priv = self->priv;
11975
11976   if (priv->parent != new_parent)
11977     {
11978       ClutterActor *old_parent;
11979
11980       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11981
11982       old_parent = priv->parent;
11983
11984       g_object_ref (self);
11985
11986       if (old_parent != NULL)
11987         {
11988          /* go through the Container implementation if this is a regular
11989           * child and not an internal one
11990           */
11991          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11992            {
11993              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11994
11995              /* this will have to call unparent() */
11996              clutter_container_remove_actor (parent, self);
11997            }
11998          else
11999            clutter_actor_remove_child_internal (old_parent, self,
12000                                                 REMOVE_CHILD_LEGACY_FLAGS);
12001         }
12002
12003       /* Note, will call set_parent() */
12004       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12005         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
12006       else
12007         clutter_actor_add_child_internal (new_parent, self,
12008                                           ADD_CHILD_LEGACY_FLAGS,
12009                                           insert_child_at_depth,
12010                                           NULL);
12011
12012       /* we emit the ::parent-set signal once */
12013       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
12014
12015       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12016
12017       /* the IN_REPARENT flag suspends state updates */
12018       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
12019
12020       g_object_unref (self);
12021    }
12022 }
12023
12024 /**
12025  * clutter_actor_contains:
12026  * @self: A #ClutterActor
12027  * @descendant: A #ClutterActor, possibly contained in @self
12028  *
12029  * Determines if @descendant is contained inside @self (either as an
12030  * immediate child, or as a deeper descendant). If @self and
12031  * @descendant point to the same actor then it will also return %TRUE.
12032  *
12033  * Return value: whether @descendent is contained within @self
12034  *
12035  * Since: 1.4
12036  */
12037 gboolean
12038 clutter_actor_contains (ClutterActor *self,
12039                         ClutterActor *descendant)
12040 {
12041   ClutterActor *actor;
12042
12043   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12044   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
12045
12046   for (actor = descendant; actor; actor = actor->priv->parent)
12047     if (actor == self)
12048       return TRUE;
12049
12050   return FALSE;
12051 }
12052
12053 /**
12054  * clutter_actor_set_child_above_sibling:
12055  * @self: a #ClutterActor
12056  * @child: a #ClutterActor child of @self
12057  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12058  *
12059  * Sets @child to be above @sibling in the list of children of @self.
12060  *
12061  * If @sibling is %NULL, @child will be the new last child of @self.
12062  *
12063  * This function is logically equivalent to removing @child and using
12064  * clutter_actor_insert_child_above(), but it will not emit signals
12065  * or change state on @child.
12066  *
12067  * Since: 1.10
12068  */
12069 void
12070 clutter_actor_set_child_above_sibling (ClutterActor *self,
12071                                        ClutterActor *child,
12072                                        ClutterActor *sibling)
12073 {
12074   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12075   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12076   g_return_if_fail (child->priv->parent == self);
12077   g_return_if_fail (child != sibling);
12078   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12079
12080   if (sibling != NULL)
12081     g_return_if_fail (sibling->priv->parent == self);
12082
12083   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12084       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12085       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12086     return;
12087
12088   /* we don't want to change the state of child, or emit signals, or
12089    * regenerate ChildMeta instances here, but we still want to follow
12090    * the correct sequence of steps encoded in remove_child() and
12091    * add_child(), so that correctness is ensured, and we only go
12092    * through one known code path.
12093    */
12094   g_object_ref (child);
12095   clutter_actor_remove_child_internal (self, child, 0);
12096   clutter_actor_add_child_internal (self, child,
12097                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12098                                     insert_child_above,
12099                                     sibling);
12100
12101   clutter_actor_queue_relayout (self);
12102 }
12103
12104 /**
12105  * clutter_actor_set_child_below_sibling:
12106  * @self: a #ClutterActor
12107  * @child: a #ClutterActor child of @self
12108  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12109  *
12110  * Sets @child to be below @sibling in the list of children of @self.
12111  *
12112  * If @sibling is %NULL, @child will be the new first child of @self.
12113  *
12114  * This function is logically equivalent to removing @self and using
12115  * clutter_actor_insert_child_below(), but it will not emit signals
12116  * or change state on @child.
12117  *
12118  * Since: 1.10
12119  */
12120 void
12121 clutter_actor_set_child_below_sibling (ClutterActor *self,
12122                                        ClutterActor *child,
12123                                        ClutterActor *sibling)
12124 {
12125   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12126   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12127   g_return_if_fail (child->priv->parent == self);
12128   g_return_if_fail (child != sibling);
12129   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12130
12131   if (sibling != NULL)
12132     g_return_if_fail (sibling->priv->parent == self);
12133
12134   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12135       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12136       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12137     return;
12138
12139   /* see the comment in set_child_above_sibling() */
12140   g_object_ref (child);
12141   clutter_actor_remove_child_internal (self, child, 0);
12142   clutter_actor_add_child_internal (self, child,
12143                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12144                                     insert_child_below,
12145                                     sibling);
12146
12147   clutter_actor_queue_relayout (self);
12148 }
12149
12150 /**
12151  * clutter_actor_set_child_at_index:
12152  * @self: a #ClutterActor
12153  * @child: a #ClutterActor child of @self
12154  * @index_: the new index for @child
12155  *
12156  * Changes the index of @child in the list of children of @self.
12157  *
12158  * This function is logically equivalent to removing @child and
12159  * calling clutter_actor_insert_child_at_index(), but it will not
12160  * emit signals or change state on @child.
12161  *
12162  * Since: 1.10
12163  */
12164 void
12165 clutter_actor_set_child_at_index (ClutterActor *self,
12166                                   ClutterActor *child,
12167                                   gint          index_)
12168 {
12169   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12170   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12171   g_return_if_fail (child->priv->parent == self);
12172   g_return_if_fail (index_ <= self->priv->n_children);
12173
12174   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12175       CLUTTER_ACTOR_IN_DESTRUCTION (child))
12176     return;
12177
12178   g_object_ref (child);
12179   clutter_actor_remove_child_internal (self, child, 0);
12180   clutter_actor_add_child_internal (self, child,
12181                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12182                                     insert_child_at_index,
12183                                     GINT_TO_POINTER (index_));
12184
12185   clutter_actor_queue_relayout (self);
12186 }
12187
12188 /**
12189  * clutter_actor_raise:
12190  * @self: A #ClutterActor
12191  * @below: (allow-none): A #ClutterActor to raise above.
12192  *
12193  * Puts @self above @below.
12194  *
12195  * Both actors must have the same parent, and the parent must implement
12196  * the #ClutterContainer interface
12197  *
12198  * This function calls clutter_container_raise_child() internally.
12199  *
12200  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12201  */
12202 void
12203 clutter_actor_raise (ClutterActor *self,
12204                      ClutterActor *below)
12205 {
12206   ClutterActor *parent;
12207
12208   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12209
12210   parent = clutter_actor_get_parent (self);
12211   if (parent == NULL)
12212     {
12213       g_warning ("%s: Actor '%s' is not inside a container",
12214                  G_STRFUNC,
12215                  _clutter_actor_get_debug_name (self));
12216       return;
12217     }
12218
12219   if (below != NULL)
12220     {
12221       if (parent != clutter_actor_get_parent (below))
12222         {
12223           g_warning ("%s Actor '%s' is not in the same container as "
12224                      "actor '%s'",
12225                      G_STRFUNC,
12226                      _clutter_actor_get_debug_name (self),
12227                      _clutter_actor_get_debug_name (below));
12228           return;
12229         }
12230     }
12231
12232   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12233 }
12234
12235 /**
12236  * clutter_actor_lower:
12237  * @self: A #ClutterActor
12238  * @above: (allow-none): A #ClutterActor to lower below
12239  *
12240  * Puts @self below @above.
12241  *
12242  * Both actors must have the same parent, and the parent must implement
12243  * the #ClutterContainer interface.
12244  *
12245  * This function calls clutter_container_lower_child() internally.
12246  *
12247  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12248  */
12249 void
12250 clutter_actor_lower (ClutterActor *self,
12251                      ClutterActor *above)
12252 {
12253   ClutterActor *parent;
12254
12255   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12256
12257   parent = clutter_actor_get_parent (self);
12258   if (parent == NULL)
12259     {
12260       g_warning ("%s: Actor of type %s is not inside a container",
12261                  G_STRFUNC,
12262                  _clutter_actor_get_debug_name (self));
12263       return;
12264     }
12265
12266   if (above)
12267     {
12268       if (parent != clutter_actor_get_parent (above))
12269         {
12270           g_warning ("%s: Actor '%s' is not in the same container as "
12271                      "actor '%s'",
12272                      G_STRFUNC,
12273                      _clutter_actor_get_debug_name (self),
12274                      _clutter_actor_get_debug_name (above));
12275           return;
12276         }
12277     }
12278
12279   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12280 }
12281
12282 /**
12283  * clutter_actor_raise_top:
12284  * @self: A #ClutterActor
12285  *
12286  * Raises @self to the top.
12287  *
12288  * This function calls clutter_actor_raise() internally.
12289  *
12290  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12291  *   a %NULL sibling, instead.
12292  */
12293 void
12294 clutter_actor_raise_top (ClutterActor *self)
12295 {
12296   clutter_actor_raise (self, NULL);
12297 }
12298
12299 /**
12300  * clutter_actor_lower_bottom:
12301  * @self: A #ClutterActor
12302  *
12303  * Lowers @self to the bottom.
12304  *
12305  * This function calls clutter_actor_lower() internally.
12306  *
12307  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12308  *   a %NULL sibling, instead.
12309  */
12310 void
12311 clutter_actor_lower_bottom (ClutterActor *self)
12312 {
12313   clutter_actor_lower (self, NULL);
12314 }
12315
12316 /*
12317  * Event handling
12318  */
12319
12320 /**
12321  * clutter_actor_event:
12322  * @actor: a #ClutterActor
12323  * @event: a #ClutterEvent
12324  * @capture: TRUE if event in in capture phase, FALSE otherwise.
12325  *
12326  * This function is used to emit an event on the main stage.
12327  * You should rarely need to use this function, except for
12328  * synthetising events.
12329  *
12330  * Return value: the return value from the signal emission: %TRUE
12331  *   if the actor handled the event, or %FALSE if the event was
12332  *   not handled
12333  *
12334  * Since: 0.6
12335  */
12336 gboolean
12337 clutter_actor_event (ClutterActor *actor,
12338                      ClutterEvent *event,
12339                      gboolean      capture)
12340 {
12341   gboolean retval = FALSE;
12342   gint signal_num = -1;
12343
12344   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12345   g_return_val_if_fail (event != NULL, FALSE);
12346
12347   g_object_ref (actor);
12348
12349   if (capture)
12350     {
12351       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12352                      event,
12353                      &retval);
12354       goto out;
12355     }
12356
12357   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12358
12359   if (!retval)
12360     {
12361       switch (event->type)
12362         {
12363         case CLUTTER_NOTHING:
12364           break;
12365         case CLUTTER_BUTTON_PRESS:
12366           signal_num = BUTTON_PRESS_EVENT;
12367           break;
12368         case CLUTTER_BUTTON_RELEASE:
12369           signal_num = BUTTON_RELEASE_EVENT;
12370           break;
12371         case CLUTTER_SCROLL:
12372           signal_num = SCROLL_EVENT;
12373           break;
12374         case CLUTTER_KEY_PRESS:
12375           signal_num = KEY_PRESS_EVENT;
12376           break;
12377         case CLUTTER_KEY_RELEASE:
12378           signal_num = KEY_RELEASE_EVENT;
12379           break;
12380         case CLUTTER_MOTION:
12381           signal_num = MOTION_EVENT;
12382           break;
12383         case CLUTTER_ENTER:
12384           signal_num = ENTER_EVENT;
12385           break;
12386         case CLUTTER_LEAVE:
12387           signal_num = LEAVE_EVENT;
12388           break;
12389         case CLUTTER_DELETE:
12390         case CLUTTER_DESTROY_NOTIFY:
12391         case CLUTTER_CLIENT_MESSAGE:
12392         default:
12393           signal_num = -1;
12394           break;
12395         }
12396
12397       if (signal_num != -1)
12398         g_signal_emit (actor, actor_signals[signal_num], 0,
12399                        event, &retval);
12400     }
12401
12402 out:
12403   g_object_unref (actor);
12404
12405   return retval;
12406 }
12407
12408 /**
12409  * clutter_actor_set_reactive:
12410  * @actor: a #ClutterActor
12411  * @reactive: whether the actor should be reactive to events
12412  *
12413  * Sets @actor as reactive. Reactive actors will receive events.
12414  *
12415  * Since: 0.6
12416  */
12417 void
12418 clutter_actor_set_reactive (ClutterActor *actor,
12419                             gboolean      reactive)
12420 {
12421   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12422
12423   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12424     return;
12425
12426   if (reactive)
12427     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12428   else
12429     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12430
12431   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12432 }
12433
12434 /**
12435  * clutter_actor_get_reactive:
12436  * @actor: a #ClutterActor
12437  *
12438  * Checks whether @actor is marked as reactive.
12439  *
12440  * Return value: %TRUE if the actor is reactive
12441  *
12442  * Since: 0.6
12443  */
12444 gboolean
12445 clutter_actor_get_reactive (ClutterActor *actor)
12446 {
12447   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12448
12449   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12450 }
12451
12452 /**
12453  * clutter_actor_get_anchor_point:
12454  * @self: a #ClutterActor
12455  * @anchor_x: (out): return location for the X coordinate of the anchor point
12456  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12457  *
12458  * Gets the current anchor point of the @actor in pixels.
12459  *
12460  * Since: 0.6
12461  */
12462 void
12463 clutter_actor_get_anchor_point (ClutterActor *self,
12464                                 gfloat       *anchor_x,
12465                                 gfloat       *anchor_y)
12466 {
12467   const ClutterTransformInfo *info;
12468
12469   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12470
12471   info = _clutter_actor_get_transform_info_or_defaults (self);
12472   clutter_anchor_coord_get_units (self, &info->anchor,
12473                                   anchor_x,
12474                                   anchor_y,
12475                                   NULL);
12476 }
12477
12478 /**
12479  * clutter_actor_set_anchor_point:
12480  * @self: a #ClutterActor
12481  * @anchor_x: X coordinate of the anchor point
12482  * @anchor_y: Y coordinate of the anchor point
12483  *
12484  * Sets an anchor point for @self. The anchor point is a point in the
12485  * coordinate space of an actor to which the actor position within its
12486  * parent is relative; the default is (0, 0), i.e. the top-left corner
12487  * of the actor.
12488  *
12489  * Since: 0.6
12490  */
12491 void
12492 clutter_actor_set_anchor_point (ClutterActor *self,
12493                                 gfloat        anchor_x,
12494                                 gfloat        anchor_y)
12495 {
12496   ClutterTransformInfo *info;
12497   ClutterActorPrivate *priv;
12498   gboolean changed = FALSE;
12499   gfloat old_anchor_x, old_anchor_y;
12500   GObject *obj;
12501
12502   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12503
12504   obj = G_OBJECT (self);
12505   priv = self->priv;
12506   info = _clutter_actor_get_transform_info (self);
12507
12508   g_object_freeze_notify (obj);
12509
12510   clutter_anchor_coord_get_units (self, &info->anchor,
12511                                   &old_anchor_x,
12512                                   &old_anchor_y,
12513                                   NULL);
12514
12515   if (info->anchor.is_fractional)
12516     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12517
12518   if (old_anchor_x != anchor_x)
12519     {
12520       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12521       changed = TRUE;
12522     }
12523
12524   if (old_anchor_y != anchor_y)
12525     {
12526       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12527       changed = TRUE;
12528     }
12529
12530   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12531
12532   if (changed)
12533     {
12534       priv->transform_valid = FALSE;
12535       clutter_actor_queue_redraw (self);
12536     }
12537
12538   g_object_thaw_notify (obj);
12539 }
12540
12541 /**
12542  * clutter_actor_get_anchor_point_gravity:
12543  * @self: a #ClutterActor
12544  *
12545  * Retrieves the anchor position expressed as a #ClutterGravity. If
12546  * the anchor point was specified using pixels or units this will
12547  * return %CLUTTER_GRAVITY_NONE.
12548  *
12549  * Return value: the #ClutterGravity used by the anchor point
12550  *
12551  * Since: 1.0
12552  */
12553 ClutterGravity
12554 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12555 {
12556   const ClutterTransformInfo *info;
12557
12558   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12559
12560   info = _clutter_actor_get_transform_info_or_defaults (self);
12561
12562   return clutter_anchor_coord_get_gravity (&info->anchor);
12563 }
12564
12565 /**
12566  * clutter_actor_move_anchor_point:
12567  * @self: a #ClutterActor
12568  * @anchor_x: X coordinate of the anchor point
12569  * @anchor_y: Y coordinate of the anchor point
12570  *
12571  * Sets an anchor point for the actor, and adjusts the actor postion so that
12572  * the relative position of the actor toward its parent remains the same.
12573  *
12574  * Since: 0.6
12575  */
12576 void
12577 clutter_actor_move_anchor_point (ClutterActor *self,
12578                                  gfloat        anchor_x,
12579                                  gfloat        anchor_y)
12580 {
12581   gfloat old_anchor_x, old_anchor_y;
12582   const ClutterTransformInfo *info;
12583
12584   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12585
12586   info = _clutter_actor_get_transform_info (self);
12587   clutter_anchor_coord_get_units (self, &info->anchor,
12588                                   &old_anchor_x,
12589                                   &old_anchor_y,
12590                                   NULL);
12591
12592   g_object_freeze_notify (G_OBJECT (self));
12593
12594   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12595
12596   if (self->priv->position_set)
12597     clutter_actor_move_by (self,
12598                            anchor_x - old_anchor_x,
12599                            anchor_y - old_anchor_y);
12600
12601   g_object_thaw_notify (G_OBJECT (self));
12602 }
12603
12604 /**
12605  * clutter_actor_move_anchor_point_from_gravity:
12606  * @self: a #ClutterActor
12607  * @gravity: #ClutterGravity.
12608  *
12609  * Sets an anchor point on the actor based on the given gravity, adjusting the
12610  * actor postion so that its relative position within its parent remains
12611  * unchanged.
12612  *
12613  * Since version 1.0 the anchor point will be stored as a gravity so
12614  * that if the actor changes size then the anchor point will move. For
12615  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12616  * and later double the size of the actor, the anchor point will move
12617  * to the bottom right.
12618  *
12619  * Since: 0.6
12620  */
12621 void
12622 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12623                                               ClutterGravity  gravity)
12624 {
12625   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12626   const ClutterTransformInfo *info;
12627   ClutterActorPrivate *priv;
12628
12629   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12630
12631   priv = self->priv;
12632   info = _clutter_actor_get_transform_info (self);
12633
12634   g_object_freeze_notify (G_OBJECT (self));
12635
12636   clutter_anchor_coord_get_units (self, &info->anchor,
12637                                   &old_anchor_x,
12638                                   &old_anchor_y,
12639                                   NULL);
12640   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12641   clutter_anchor_coord_get_units (self, &info->anchor,
12642                                   &new_anchor_x,
12643                                   &new_anchor_y,
12644                                   NULL);
12645
12646   if (priv->position_set)
12647     clutter_actor_move_by (self,
12648                            new_anchor_x - old_anchor_x,
12649                            new_anchor_y - old_anchor_y);
12650
12651   g_object_thaw_notify (G_OBJECT (self));
12652 }
12653
12654 /**
12655  * clutter_actor_set_anchor_point_from_gravity:
12656  * @self: a #ClutterActor
12657  * @gravity: #ClutterGravity.
12658  *
12659  * Sets an anchor point on the actor, based on the given gravity (this is a
12660  * convenience function wrapping clutter_actor_set_anchor_point()).
12661  *
12662  * Since version 1.0 the anchor point will be stored as a gravity so
12663  * that if the actor changes size then the anchor point will move. For
12664  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12665  * and later double the size of the actor, the anchor point will move
12666  * to the bottom right.
12667  *
12668  * Since: 0.6
12669  */
12670 void
12671 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12672                                              ClutterGravity  gravity)
12673 {
12674   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12675
12676   if (gravity == CLUTTER_GRAVITY_NONE)
12677     clutter_actor_set_anchor_point (self, 0, 0);
12678   else
12679     {
12680       GObject *obj = G_OBJECT (self);
12681       ClutterTransformInfo *info;
12682
12683       g_object_freeze_notify (obj);
12684
12685       info = _clutter_actor_get_transform_info (self);
12686       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12687
12688       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12689       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12690       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12691
12692       self->priv->transform_valid = FALSE;
12693
12694       clutter_actor_queue_redraw (self);
12695
12696       g_object_thaw_notify (obj);
12697     }
12698 }
12699
12700 static void
12701 clutter_actor_store_content_box (ClutterActor *self,
12702                                  const ClutterActorBox *box)
12703 {
12704   if (box != NULL)
12705     {
12706       self->priv->content_box = *box;
12707       self->priv->content_box_valid = TRUE;
12708     }
12709   else
12710     self->priv->content_box_valid = FALSE;
12711
12712   clutter_actor_queue_redraw (self);
12713
12714   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12715 }
12716
12717 static void
12718 clutter_container_iface_init (ClutterContainerIface *iface)
12719 {
12720   /* we don't override anything, as ClutterContainer already has a default
12721    * implementation that we can use, and which calls into our own API.
12722    */
12723 }
12724
12725 typedef enum
12726 {
12727   PARSE_X,
12728   PARSE_Y,
12729   PARSE_WIDTH,
12730   PARSE_HEIGHT,
12731   PARSE_ANCHOR_X,
12732   PARSE_ANCHOR_Y
12733 } ParseDimension;
12734
12735 static gfloat
12736 parse_units (ClutterActor   *self,
12737              ParseDimension  dimension,
12738              JsonNode       *node)
12739 {
12740   GValue value = G_VALUE_INIT;
12741   gfloat retval = 0;
12742
12743   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12744     return 0;
12745
12746   json_node_get_value (node, &value);
12747
12748   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12749     {
12750       retval = (gfloat) g_value_get_int64 (&value);
12751     }
12752   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12753     {
12754       retval = g_value_get_double (&value);
12755     }
12756   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12757     {
12758       ClutterUnits units;
12759       gboolean res;
12760
12761       res = clutter_units_from_string (&units, g_value_get_string (&value));
12762       if (res)
12763         retval = clutter_units_to_pixels (&units);
12764       else
12765         {
12766           g_warning ("Invalid value '%s': integers, strings or floating point "
12767                      "values can be used for the x, y, width and height "
12768                      "properties. Valid modifiers for strings are 'px', 'mm', "
12769                      "'pt' and 'em'.",
12770                      g_value_get_string (&value));
12771           retval = 0;
12772         }
12773     }
12774   else
12775     {
12776       g_warning ("Invalid value of type '%s': integers, strings of floating "
12777                  "point values can be used for the x, y, width, height "
12778                  "anchor-x and anchor-y properties.",
12779                  g_type_name (G_VALUE_TYPE (&value)));
12780     }
12781
12782   g_value_unset (&value);
12783
12784   return retval;
12785 }
12786
12787 typedef struct {
12788   ClutterRotateAxis axis;
12789
12790   gdouble angle;
12791
12792   gfloat center_x;
12793   gfloat center_y;
12794   gfloat center_z;
12795 } RotationInfo;
12796
12797 static inline gboolean
12798 parse_rotation_array (ClutterActor *actor,
12799                       JsonArray    *array,
12800                       RotationInfo *info)
12801 {
12802   JsonNode *element;
12803
12804   if (json_array_get_length (array) != 2)
12805     return FALSE;
12806
12807   /* angle */
12808   element = json_array_get_element (array, 0);
12809   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12810     info->angle = json_node_get_double (element);
12811   else
12812     return FALSE;
12813
12814   /* center */
12815   element = json_array_get_element (array, 1);
12816   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12817     {
12818       JsonArray *center = json_node_get_array (element);
12819
12820       if (json_array_get_length (center) != 2)
12821         return FALSE;
12822
12823       switch (info->axis)
12824         {
12825         case CLUTTER_X_AXIS:
12826           info->center_y = parse_units (actor, PARSE_Y,
12827                                         json_array_get_element (center, 0));
12828           info->center_z = parse_units (actor, PARSE_Y,
12829                                         json_array_get_element (center, 1));
12830           return TRUE;
12831
12832         case CLUTTER_Y_AXIS:
12833           info->center_x = parse_units (actor, PARSE_X,
12834                                         json_array_get_element (center, 0));
12835           info->center_z = parse_units (actor, PARSE_X,
12836                                         json_array_get_element (center, 1));
12837           return TRUE;
12838
12839         case CLUTTER_Z_AXIS:
12840           info->center_x = parse_units (actor, PARSE_X,
12841                                         json_array_get_element (center, 0));
12842           info->center_y = parse_units (actor, PARSE_Y,
12843                                         json_array_get_element (center, 1));
12844           return TRUE;
12845         }
12846     }
12847
12848   return FALSE;
12849 }
12850
12851 static gboolean
12852 parse_rotation (ClutterActor *actor,
12853                 JsonNode     *node,
12854                 RotationInfo *info)
12855 {
12856   JsonArray *array;
12857   guint len, i;
12858   gboolean retval = FALSE;
12859
12860   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12861     {
12862       g_warning ("Invalid node of type '%s' found, expecting an array",
12863                  json_node_type_name (node));
12864       return FALSE;
12865     }
12866
12867   array = json_node_get_array (node);
12868   len = json_array_get_length (array);
12869
12870   for (i = 0; i < len; i++)
12871     {
12872       JsonNode *element = json_array_get_element (array, i);
12873       JsonObject *object;
12874       JsonNode *member;
12875
12876       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12877         {
12878           g_warning ("Invalid node of type '%s' found, expecting an object",
12879                      json_node_type_name (element));
12880           return FALSE;
12881         }
12882
12883       object = json_node_get_object (element);
12884
12885       if (json_object_has_member (object, "x-axis"))
12886         {
12887           member = json_object_get_member (object, "x-axis");
12888
12889           info->axis = CLUTTER_X_AXIS;
12890
12891           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12892             {
12893               info->angle = json_node_get_double (member);
12894               retval = TRUE;
12895             }
12896           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12897             retval = parse_rotation_array (actor,
12898                                            json_node_get_array (member),
12899                                            info);
12900           else
12901             retval = FALSE;
12902         }
12903       else if (json_object_has_member (object, "y-axis"))
12904         {
12905           member = json_object_get_member (object, "y-axis");
12906
12907           info->axis = CLUTTER_Y_AXIS;
12908
12909           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12910             {
12911               info->angle = json_node_get_double (member);
12912               retval = TRUE;
12913             }
12914           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12915             retval = parse_rotation_array (actor,
12916                                            json_node_get_array (member),
12917                                            info);
12918           else
12919             retval = FALSE;
12920         }
12921       else if (json_object_has_member (object, "z-axis"))
12922         {
12923           member = json_object_get_member (object, "z-axis");
12924
12925           info->axis = CLUTTER_Z_AXIS;
12926
12927           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12928             {
12929               info->angle = json_node_get_double (member);
12930               retval = TRUE;
12931             }
12932           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12933             retval = parse_rotation_array (actor,
12934                                            json_node_get_array (member),
12935                                            info);
12936           else
12937             retval = FALSE;
12938         }
12939     }
12940
12941   return retval;
12942 }
12943
12944 static GSList *
12945 parse_actor_metas (ClutterScript *script,
12946                    ClutterActor  *actor,
12947                    JsonNode      *node)
12948 {
12949   GList *elements, *l;
12950   GSList *retval = NULL;
12951
12952   if (!JSON_NODE_HOLDS_ARRAY (node))
12953     return NULL;
12954
12955   elements = json_array_get_elements (json_node_get_array (node));
12956
12957   for (l = elements; l != NULL; l = l->next)
12958     {
12959       JsonNode *element = l->data;
12960       const gchar *id_ = _clutter_script_get_id_from_node (element);
12961       GObject *meta;
12962
12963       if (id_ == NULL || *id_ == '\0')
12964         continue;
12965
12966       meta = clutter_script_get_object (script, id_);
12967       if (meta == NULL)
12968         continue;
12969
12970       retval = g_slist_prepend (retval, meta);
12971     }
12972
12973   g_list_free (elements);
12974
12975   return g_slist_reverse (retval);
12976 }
12977
12978 static GSList *
12979 parse_behaviours (ClutterScript *script,
12980                   ClutterActor  *actor,
12981                   JsonNode      *node)
12982 {
12983   GList *elements, *l;
12984   GSList *retval = NULL;
12985
12986   if (!JSON_NODE_HOLDS_ARRAY (node))
12987     return NULL;
12988
12989   elements = json_array_get_elements (json_node_get_array (node));
12990
12991   for (l = elements; l != NULL; l = l->next)
12992     {
12993       JsonNode *element = l->data;
12994       const gchar *id_ = _clutter_script_get_id_from_node (element);
12995       GObject *behaviour;
12996
12997       if (id_ == NULL || *id_ == '\0')
12998         continue;
12999
13000       behaviour = clutter_script_get_object (script, id_);
13001       if (behaviour == NULL)
13002         continue;
13003
13004       retval = g_slist_prepend (retval, behaviour);
13005     }
13006
13007   g_list_free (elements);
13008
13009   return g_slist_reverse (retval);
13010 }
13011
13012 static gboolean
13013 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
13014                                  ClutterScript     *script,
13015                                  GValue            *value,
13016                                  const gchar       *name,
13017                                  JsonNode          *node)
13018 {
13019   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13020   gboolean retval = FALSE;
13021
13022   if ((name[0] == 'x' && name[1] == '\0') ||
13023       (name[0] == 'y' && name[1] == '\0') ||
13024       (strcmp (name, "width") == 0) ||
13025       (strcmp (name, "height") == 0) ||
13026       (strcmp (name, "anchor_x") == 0) ||
13027       (strcmp (name, "anchor_y") == 0))
13028     {
13029       ParseDimension dimension;
13030       gfloat units;
13031
13032       if (name[0] == 'x')
13033         dimension = PARSE_X;
13034       else if (name[0] == 'y')
13035         dimension = PARSE_Y;
13036       else if (name[0] == 'w')
13037         dimension = PARSE_WIDTH;
13038       else if (name[0] == 'h')
13039         dimension = PARSE_HEIGHT;
13040       else if (name[0] == 'a' && name[7] == 'x')
13041         dimension = PARSE_ANCHOR_X;
13042       else if (name[0] == 'a' && name[7] == 'y')
13043         dimension = PARSE_ANCHOR_Y;
13044       else
13045         return FALSE;
13046
13047       units = parse_units (actor, dimension, node);
13048
13049       /* convert back to pixels: all properties are pixel-based */
13050       g_value_init (value, G_TYPE_FLOAT);
13051       g_value_set_float (value, units);
13052
13053       retval = TRUE;
13054     }
13055   else if (strcmp (name, "rotation") == 0)
13056     {
13057       RotationInfo *info;
13058
13059       info = g_slice_new0 (RotationInfo);
13060       retval = parse_rotation (actor, node, info);
13061
13062       if (retval)
13063         {
13064           g_value_init (value, G_TYPE_POINTER);
13065           g_value_set_pointer (value, info);
13066         }
13067       else
13068         g_slice_free (RotationInfo, info);
13069     }
13070   else if (strcmp (name, "behaviours") == 0)
13071     {
13072       GSList *l;
13073
13074 #ifdef CLUTTER_ENABLE_DEBUG
13075       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
13076         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
13077                                      "and it should not be used in newly "
13078                                      "written ClutterScript definitions.");
13079 #endif
13080
13081       l = parse_behaviours (script, actor, node);
13082
13083       g_value_init (value, G_TYPE_POINTER);
13084       g_value_set_pointer (value, l);
13085
13086       retval = TRUE;
13087     }
13088   else if (strcmp (name, "actions") == 0 ||
13089            strcmp (name, "constraints") == 0 ||
13090            strcmp (name, "effects") == 0)
13091     {
13092       GSList *l;
13093
13094       l = parse_actor_metas (script, actor, node);
13095
13096       g_value_init (value, G_TYPE_POINTER);
13097       g_value_set_pointer (value, l);
13098
13099       retval = TRUE;
13100     }
13101
13102   return retval;
13103 }
13104
13105 static void
13106 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
13107                                    ClutterScript     *script,
13108                                    const gchar       *name,
13109                                    const GValue      *value)
13110 {
13111   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13112
13113 #ifdef CLUTTER_ENABLE_DEBUG
13114   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
13115     {
13116       gchar *tmp = g_strdup_value_contents (value);
13117
13118       CLUTTER_NOTE (SCRIPT,
13119                     "in ClutterActor::set_custom_property('%s') = %s",
13120                     name,
13121                     tmp);
13122
13123       g_free (tmp);
13124     }
13125 #endif /* CLUTTER_ENABLE_DEBUG */
13126
13127   if (strcmp (name, "rotation") == 0)
13128     {
13129       RotationInfo *info;
13130
13131       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13132         return;
13133
13134       info = g_value_get_pointer (value);
13135
13136       clutter_actor_set_rotation (actor,
13137                                   info->axis, info->angle,
13138                                   info->center_x,
13139                                   info->center_y,
13140                                   info->center_z);
13141
13142       g_slice_free (RotationInfo, info);
13143
13144       return;
13145     }
13146
13147   if (strcmp (name, "behaviours") == 0)
13148     {
13149       GSList *behaviours, *l;
13150
13151       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13152         return;
13153
13154       behaviours = g_value_get_pointer (value);
13155       for (l = behaviours; l != NULL; l = l->next)
13156         {
13157           ClutterBehaviour *behaviour = l->data;
13158
13159           clutter_behaviour_apply (behaviour, actor);
13160         }
13161
13162       g_slist_free (behaviours);
13163
13164       return;
13165     }
13166
13167   if (strcmp (name, "actions") == 0 ||
13168       strcmp (name, "constraints") == 0 ||
13169       strcmp (name, "effects") == 0)
13170     {
13171       GSList *metas, *l;
13172
13173       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13174         return;
13175
13176       metas = g_value_get_pointer (value);
13177       for (l = metas; l != NULL; l = l->next)
13178         {
13179           if (name[0] == 'a')
13180             clutter_actor_add_action (actor, l->data);
13181
13182           if (name[0] == 'c')
13183             clutter_actor_add_constraint (actor, l->data);
13184
13185           if (name[0] == 'e')
13186             clutter_actor_add_effect (actor, l->data);
13187         }
13188
13189       g_slist_free (metas);
13190
13191       return;
13192     }
13193
13194   g_object_set_property (G_OBJECT (scriptable), name, value);
13195 }
13196
13197 static void
13198 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13199 {
13200   iface->parse_custom_node = clutter_actor_parse_custom_node;
13201   iface->set_custom_property = clutter_actor_set_custom_property;
13202 }
13203
13204 static ClutterActorMeta *
13205 get_meta_from_animation_property (ClutterActor  *actor,
13206                                   const gchar   *name,
13207                                   gchar        **name_p)
13208 {
13209   ClutterActorPrivate *priv = actor->priv;
13210   ClutterActorMeta *meta = NULL;
13211   gchar **tokens;
13212
13213   /* if this is not a special property, fall through */
13214   if (name[0] != '@')
13215     return NULL;
13216
13217   /* detect the properties named using the following spec:
13218    *
13219    *   @<section>.<meta-name>.<property-name>
13220    *
13221    * where <section> can be one of the following:
13222    *
13223    *   - actions
13224    *   - constraints
13225    *   - effects
13226    *
13227    * and <meta-name> is the name set on a specific ActorMeta
13228    */
13229
13230   tokens = g_strsplit (name + 1, ".", -1);
13231   if (tokens == NULL || g_strv_length (tokens) != 3)
13232     {
13233       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13234                     name + 1);
13235       g_strfreev (tokens);
13236       return NULL;
13237     }
13238
13239   if (strcmp (tokens[0], "actions") == 0)
13240     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13241
13242   if (strcmp (tokens[0], "constraints") == 0)
13243     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13244
13245   if (strcmp (tokens[0], "effects") == 0)
13246     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13247
13248   if (name_p != NULL)
13249     *name_p = g_strdup (tokens[2]);
13250
13251   CLUTTER_NOTE (ANIMATION,
13252                 "Looking for property '%s' of object '%s' in section '%s'",
13253                 tokens[2],
13254                 tokens[1],
13255                 tokens[0]);
13256
13257   g_strfreev (tokens);
13258
13259   return meta;
13260 }
13261
13262 static GParamSpec *
13263 clutter_actor_find_property (ClutterAnimatable *animatable,
13264                              const gchar       *property_name)
13265 {
13266   ClutterActorMeta *meta = NULL;
13267   GObjectClass *klass = NULL;
13268   GParamSpec *pspec = NULL;
13269   gchar *p_name = NULL;
13270
13271   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13272                                            property_name,
13273                                            &p_name);
13274
13275   if (meta != NULL)
13276     {
13277       klass = G_OBJECT_GET_CLASS (meta);
13278
13279       pspec = g_object_class_find_property (klass, p_name);
13280     }
13281   else
13282     {
13283       klass = G_OBJECT_GET_CLASS (animatable);
13284
13285       pspec = g_object_class_find_property (klass, property_name);
13286     }
13287
13288   g_free (p_name);
13289
13290   return pspec;
13291 }
13292
13293 static void
13294 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13295                                  const gchar       *property_name,
13296                                  GValue            *initial)
13297 {
13298   ClutterActorMeta *meta = NULL;
13299   gchar *p_name = NULL;
13300
13301   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13302                                            property_name,
13303                                            &p_name);
13304
13305   if (meta != NULL)
13306     g_object_get_property (G_OBJECT (meta), p_name, initial);
13307   else
13308     g_object_get_property (G_OBJECT (animatable), property_name, initial);
13309
13310   g_free (p_name);
13311 }
13312
13313 /*
13314  * clutter_actor_set_animatable_property:
13315  * @actor: a #ClutterActor
13316  * @prop_id: the paramspec id
13317  * @value: the value to set
13318  * @pspec: the paramspec
13319  *
13320  * Sets values of animatable properties.
13321  *
13322  * This is a variant of clutter_actor_set_property() that gets called
13323  * by the #ClutterAnimatable implementation of #ClutterActor for the
13324  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13325  * #GParamSpec.
13326  *
13327  * Unlike the implementation of #GObjectClass.set_property(), this
13328  * function will not update the interval if a transition involving an
13329  * animatable property is in progress - this avoids cycles with the
13330  * transition API calling the public API.
13331  */
13332 static void
13333 clutter_actor_set_animatable_property (ClutterActor *actor,
13334                                        guint         prop_id,
13335                                        const GValue *value,
13336                                        GParamSpec   *pspec)
13337 {
13338   GObject *obj = G_OBJECT (actor);
13339
13340   g_object_freeze_notify (obj);
13341
13342   switch (prop_id)
13343     {
13344     case PROP_X:
13345       clutter_actor_set_x_internal (actor, g_value_get_float (value));
13346       break;
13347
13348     case PROP_Y:
13349       clutter_actor_set_y_internal (actor, g_value_get_float (value));
13350       break;
13351
13352     case PROP_POSITION:
13353       clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13354       break;
13355
13356     case PROP_WIDTH:
13357       clutter_actor_set_width_internal (actor, g_value_get_float (value));
13358       break;
13359
13360     case PROP_HEIGHT:
13361       clutter_actor_set_height_internal (actor, g_value_get_float (value));
13362       break;
13363
13364     case PROP_SIZE:
13365       clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13366       break;
13367
13368     case PROP_ALLOCATION:
13369       clutter_actor_allocate_internal (actor,
13370                                        g_value_get_boxed (value),
13371                                        actor->priv->allocation_flags);
13372       break;
13373
13374     case PROP_DEPTH:
13375       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13376       break;
13377
13378     case PROP_OPACITY:
13379       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13380       break;
13381
13382     case PROP_BACKGROUND_COLOR:
13383       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13384       break;
13385
13386     case PROP_SCALE_X:
13387       clutter_actor_set_scale_factor_internal (actor,
13388                                                g_value_get_double (value),
13389                                                pspec);
13390       break;
13391
13392     case PROP_SCALE_Y:
13393       clutter_actor_set_scale_factor_internal (actor,
13394                                                g_value_get_double (value),
13395                                                pspec);
13396       break;
13397
13398     case PROP_ROTATION_ANGLE_X:
13399       clutter_actor_set_rotation_angle_internal (actor,
13400                                                  CLUTTER_X_AXIS,
13401                                                  g_value_get_double (value));
13402       break;
13403
13404     case PROP_ROTATION_ANGLE_Y:
13405       clutter_actor_set_rotation_angle_internal (actor,
13406                                                  CLUTTER_Y_AXIS,
13407                                                  g_value_get_double (value));
13408       break;
13409
13410     case PROP_ROTATION_ANGLE_Z:
13411       clutter_actor_set_rotation_angle_internal (actor,
13412                                                  CLUTTER_Z_AXIS,
13413                                                  g_value_get_double (value));
13414       break;
13415
13416     case PROP_CONTENT_BOX:
13417       clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13418       break;
13419
13420     default:
13421       g_object_set_property (obj, pspec->name, value);
13422       break;
13423     }
13424
13425   g_object_thaw_notify (obj);
13426 }
13427
13428 static void
13429 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13430                                const gchar       *property_name,
13431                                const GValue      *final)
13432 {
13433   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13434   ClutterActorMeta *meta = NULL;
13435   gchar *p_name = NULL;
13436
13437   meta = get_meta_from_animation_property (actor,
13438                                            property_name,
13439                                            &p_name);
13440   if (meta != NULL)
13441     g_object_set_property (G_OBJECT (meta), p_name, final);
13442   else
13443     {
13444       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13445       GParamSpec *pspec;
13446
13447       pspec = g_object_class_find_property (obj_class, property_name);
13448
13449       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13450         {
13451           /* XXX - I'm going to the special hell for this */
13452           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13453         }
13454       else
13455         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13456     }
13457
13458   g_free (p_name);
13459 }
13460
13461 static void
13462 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13463 {
13464   iface->find_property = clutter_actor_find_property;
13465   iface->get_initial_state = clutter_actor_get_initial_state;
13466   iface->set_final_state = clutter_actor_set_final_state;
13467 }
13468
13469 /**
13470  * clutter_actor_transform_stage_point:
13471  * @self: A #ClutterActor
13472  * @x: (in): x screen coordinate of the point to unproject
13473  * @y: (in): y screen coordinate of the point to unproject
13474  * @x_out: (out): return location for the unprojected x coordinance
13475  * @y_out: (out): return location for the unprojected y coordinance
13476  *
13477  * This function translates screen coordinates (@x, @y) to
13478  * coordinates relative to the actor. For example, it can be used to translate
13479  * screen events from global screen coordinates into actor-local coordinates.
13480  *
13481  * The conversion can fail, notably if the transform stack results in the
13482  * actor being projected on the screen as a mere line.
13483  *
13484  * The conversion should not be expected to be pixel-perfect due to the
13485  * nature of the operation. In general the error grows when the skewing
13486  * of the actor rectangle on screen increases.
13487  *
13488  * <note><para>This function can be computationally intensive.</para></note>
13489  *
13490  * <note><para>This function only works when the allocation is up-to-date,
13491  * i.e. inside of paint().</para></note>
13492  *
13493  * Return value: %TRUE if conversion was successful.
13494  *
13495  * Since: 0.6
13496  */
13497 gboolean
13498 clutter_actor_transform_stage_point (ClutterActor *self,
13499                                      gfloat        x,
13500                                      gfloat        y,
13501                                      gfloat       *x_out,
13502                                      gfloat       *y_out)
13503 {
13504   ClutterVertex v[4];
13505   float ST[3][3];
13506   float RQ[3][3];
13507   int du, dv, xi, yi;
13508   float px, py;
13509   float xf, yf, wf, det;
13510   ClutterActorPrivate *priv;
13511
13512   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13513
13514   priv = self->priv;
13515
13516   /* This implementation is based on the quad -> quad projection algorithm
13517    * described by Paul Heckbert in:
13518    *
13519    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13520    *
13521    * and the sample implementation at:
13522    *
13523    *   http://www.cs.cmu.edu/~ph/src/texfund/
13524    *
13525    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13526    * quad to rectangle only, which significantly simplifies things; the
13527    * function calls have been unrolled, and most of the math is done in fixed
13528    * point.
13529    */
13530
13531   clutter_actor_get_abs_allocation_vertices (self, v);
13532
13533   /* Keeping these as ints simplifies the multiplication (no significant
13534    * loss of precision here).
13535    */
13536   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13537   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13538
13539   if (!du || !dv)
13540     return FALSE;
13541
13542 #define UX2FP(x)        (x)
13543 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13544
13545   /* First, find mapping from unit uv square to xy quadrilateral; this
13546    * equivalent to the pmap_square_quad() functions in the sample
13547    * implementation, which we can simplify, since our target is always
13548    * a rectangle.
13549    */
13550   px = v[0].x - v[1].x + v[3].x - v[2].x;
13551   py = v[0].y - v[1].y + v[3].y - v[2].y;
13552
13553   if (!px && !py)
13554     {
13555       /* affine transform */
13556       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13557       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13558       RQ[2][0] = UX2FP (v[0].x);
13559       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13560       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13561       RQ[2][1] = UX2FP (v[0].y);
13562       RQ[0][2] = 0;
13563       RQ[1][2] = 0;
13564       RQ[2][2] = 1.0;
13565     }
13566   else
13567     {
13568       /* projective transform */
13569       double dx1, dx2, dy1, dy2, del;
13570
13571       dx1 = UX2FP (v[1].x - v[3].x);
13572       dx2 = UX2FP (v[2].x - v[3].x);
13573       dy1 = UX2FP (v[1].y - v[3].y);
13574       dy2 = UX2FP (v[2].y - v[3].y);
13575
13576       del = DET2FP (dx1, dx2, dy1, dy2);
13577       if (!del)
13578         return FALSE;
13579
13580       /*
13581        * The division here needs to be done in floating point for
13582        * precisions reasons.
13583        */
13584       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13585       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13586       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13587       RQ[2][2] = 1.0;
13588       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13589       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13590       RQ[2][0] = UX2FP (v[0].x);
13591       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13592       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13593       RQ[2][1] = UX2FP (v[0].y);
13594     }
13595
13596   /*
13597    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13598    * square. Since our rectangle is based at 0,0 we only need to scale.
13599    */
13600   RQ[0][0] /= du;
13601   RQ[1][0] /= dv;
13602   RQ[0][1] /= du;
13603   RQ[1][1] /= dv;
13604   RQ[0][2] /= du;
13605   RQ[1][2] /= dv;
13606
13607   /*
13608    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13609    * inverse of that.
13610    */
13611   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13612   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13613   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13614   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13615   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13616   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13617   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13618   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13619   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13620
13621   /*
13622    * Check the resulting matrix is OK.
13623    */
13624   det = (RQ[0][0] * ST[0][0])
13625       + (RQ[0][1] * ST[0][1])
13626       + (RQ[0][2] * ST[0][2]);
13627   if (!det)
13628     return FALSE;
13629
13630   /*
13631    * Now transform our point with the ST matrix; the notional w
13632    * coordinate is 1, hence the last part is simply added.
13633    */
13634   xi = (int) x;
13635   yi = (int) y;
13636
13637   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13638   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13639   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13640
13641   if (x_out)
13642     *x_out = xf / wf;
13643
13644   if (y_out)
13645     *y_out = yf / wf;
13646
13647 #undef UX2FP
13648 #undef DET2FP
13649
13650   return TRUE;
13651 }
13652
13653 /**
13654  * clutter_actor_is_rotated:
13655  * @self: a #ClutterActor
13656  *
13657  * Checks whether any rotation is applied to the actor.
13658  *
13659  * Return value: %TRUE if the actor is rotated.
13660  *
13661  * Since: 0.6
13662  */
13663 gboolean
13664 clutter_actor_is_rotated (ClutterActor *self)
13665 {
13666   const ClutterTransformInfo *info;
13667
13668   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13669
13670   info = _clutter_actor_get_transform_info_or_defaults (self);
13671
13672   if (info->rx_angle || info->ry_angle || info->rz_angle)
13673     return TRUE;
13674
13675   return FALSE;
13676 }
13677
13678 /**
13679  * clutter_actor_is_scaled:
13680  * @self: a #ClutterActor
13681  *
13682  * Checks whether the actor is scaled in either dimension.
13683  *
13684  * Return value: %TRUE if the actor is scaled.
13685  *
13686  * Since: 0.6
13687  */
13688 gboolean
13689 clutter_actor_is_scaled (ClutterActor *self)
13690 {
13691   const ClutterTransformInfo *info;
13692
13693   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13694
13695   info = _clutter_actor_get_transform_info_or_defaults (self);
13696
13697   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13698     return TRUE;
13699
13700   return FALSE;
13701 }
13702
13703 ClutterActor *
13704 _clutter_actor_get_stage_internal (ClutterActor *actor)
13705 {
13706   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13707     actor = actor->priv->parent;
13708
13709   return actor;
13710 }
13711
13712 /**
13713  * clutter_actor_get_stage:
13714  * @actor: a #ClutterActor
13715  *
13716  * Retrieves the #ClutterStage where @actor is contained.
13717  *
13718  * Return value: (transfer none) (type Clutter.Stage): the stage
13719  *   containing the actor, or %NULL
13720  *
13721  * Since: 0.8
13722  */
13723 ClutterActor *
13724 clutter_actor_get_stage (ClutterActor *actor)
13725 {
13726   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13727
13728   return _clutter_actor_get_stage_internal (actor);
13729 }
13730
13731 /**
13732  * clutter_actor_allocate_available_size:
13733  * @self: a #ClutterActor
13734  * @x: the actor's X coordinate
13735  * @y: the actor's Y coordinate
13736  * @available_width: the maximum available width, or -1 to use the
13737  *   actor's natural width
13738  * @available_height: the maximum available height, or -1 to use the
13739  *   actor's natural height
13740  * @flags: flags controlling the allocation
13741  *
13742  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13743  * preferred size, but limiting it to the maximum available width
13744  * and height provided.
13745  *
13746  * This function will do the right thing when dealing with the
13747  * actor's request mode.
13748  *
13749  * The implementation of this function is equivalent to:
13750  *
13751  * |[
13752  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13753  *     {
13754  *       clutter_actor_get_preferred_width (self, available_height,
13755  *                                          &amp;min_width,
13756  *                                          &amp;natural_width);
13757  *       width = CLAMP (natural_width, min_width, available_width);
13758  *
13759  *       clutter_actor_get_preferred_height (self, width,
13760  *                                           &amp;min_height,
13761  *                                           &amp;natural_height);
13762  *       height = CLAMP (natural_height, min_height, available_height);
13763  *     }
13764  *   else
13765  *     {
13766  *       clutter_actor_get_preferred_height (self, available_width,
13767  *                                           &amp;min_height,
13768  *                                           &amp;natural_height);
13769  *       height = CLAMP (natural_height, min_height, available_height);
13770  *
13771  *       clutter_actor_get_preferred_width (self, height,
13772  *                                          &amp;min_width,
13773  *                                          &amp;natural_width);
13774  *       width = CLAMP (natural_width, min_width, available_width);
13775  *     }
13776  *
13777  *   box.x1 = x; box.y1 = y;
13778  *   box.x2 = box.x1 + available_width;
13779  *   box.y2 = box.y1 + available_height;
13780  *   clutter_actor_allocate (self, &amp;box, flags);
13781  * ]|
13782  *
13783  * This function can be used by fluid layout managers to allocate
13784  * an actor's preferred size without making it bigger than the area
13785  * available for the container.
13786  *
13787  * Since: 1.0
13788  */
13789 void
13790 clutter_actor_allocate_available_size (ClutterActor           *self,
13791                                        gfloat                  x,
13792                                        gfloat                  y,
13793                                        gfloat                  available_width,
13794                                        gfloat                  available_height,
13795                                        ClutterAllocationFlags  flags)
13796 {
13797   ClutterActorPrivate *priv;
13798   gfloat width, height;
13799   gfloat min_width, min_height;
13800   gfloat natural_width, natural_height;
13801   ClutterActorBox box;
13802
13803   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13804
13805   priv = self->priv;
13806
13807   width = height = 0.0;
13808
13809   switch (priv->request_mode)
13810     {
13811     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13812       clutter_actor_get_preferred_width (self, available_height,
13813                                          &min_width,
13814                                          &natural_width);
13815       width  = CLAMP (natural_width, min_width, available_width);
13816
13817       clutter_actor_get_preferred_height (self, width,
13818                                           &min_height,
13819                                           &natural_height);
13820       height = CLAMP (natural_height, min_height, available_height);
13821       break;
13822
13823     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13824       clutter_actor_get_preferred_height (self, available_width,
13825                                           &min_height,
13826                                           &natural_height);
13827       height = CLAMP (natural_height, min_height, available_height);
13828
13829       clutter_actor_get_preferred_width (self, height,
13830                                          &min_width,
13831                                          &natural_width);
13832       width  = CLAMP (natural_width, min_width, available_width);
13833       break;
13834     }
13835
13836
13837   box.x1 = x;
13838   box.y1 = y;
13839   box.x2 = box.x1 + width;
13840   box.y2 = box.y1 + height;
13841   clutter_actor_allocate (self, &box, flags);
13842 }
13843
13844 /**
13845  * clutter_actor_allocate_preferred_size:
13846  * @self: a #ClutterActor
13847  * @flags: flags controlling the allocation
13848  *
13849  * Allocates the natural size of @self.
13850  *
13851  * This function is a utility call for #ClutterActor implementations
13852  * that allocates the actor's preferred natural size. It can be used
13853  * by fixed layout managers (like #ClutterGroup or so called
13854  * 'composite actors') inside the ClutterActor::allocate
13855  * implementation to give each child exactly how much space it
13856  * requires.
13857  *
13858  * This function is not meant to be used by applications. It is also
13859  * not meant to be used outside the implementation of the
13860  * ClutterActor::allocate virtual function.
13861  *
13862  * Since: 0.8
13863  */
13864 void
13865 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13866                                        ClutterAllocationFlags  flags)
13867 {
13868   gfloat actor_x, actor_y;
13869   gfloat natural_width, natural_height;
13870   ClutterActorBox actor_box;
13871
13872   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13873
13874   actor_x = clutter_actor_get_x (self);
13875   actor_y = clutter_actor_get_y (self);
13876
13877   clutter_actor_get_preferred_size (self,
13878                                     NULL, NULL,
13879                                     &natural_width,
13880                                     &natural_height);
13881
13882   actor_box.x1 = actor_x;
13883   actor_box.y1 = actor_y;
13884   actor_box.x2 = actor_box.x1 + natural_width;
13885   actor_box.y2 = actor_box.y1 + natural_height;
13886
13887   clutter_actor_allocate (self, &actor_box, flags);
13888 }
13889
13890 /**
13891  * clutter_actor_allocate_align_fill:
13892  * @self: a #ClutterActor
13893  * @box: a #ClutterActorBox, containing the available width and height
13894  * @x_align: the horizontal alignment, between 0 and 1
13895  * @y_align: the vertical alignment, between 0 and 1
13896  * @x_fill: whether the actor should fill horizontally
13897  * @y_fill: whether the actor should fill vertically
13898  * @flags: allocation flags to be passed to clutter_actor_allocate()
13899  *
13900  * Allocates @self by taking into consideration the available allocation
13901  * area; an alignment factor on either axis; and whether the actor should
13902  * fill the allocation on either axis.
13903  *
13904  * The @box should contain the available allocation width and height;
13905  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13906  * allocation will be offset by their value.
13907  *
13908  * This function takes into consideration the geometry request specified by
13909  * the #ClutterActor:request-mode property, and the text direction.
13910  *
13911  * This function is useful for fluid layout managers, like #ClutterBinLayout
13912  * or #ClutterTableLayout
13913  *
13914  * Since: 1.4
13915  */
13916 void
13917 clutter_actor_allocate_align_fill (ClutterActor           *self,
13918                                    const ClutterActorBox  *box,
13919                                    gdouble                 x_align,
13920                                    gdouble                 y_align,
13921                                    gboolean                x_fill,
13922                                    gboolean                y_fill,
13923                                    ClutterAllocationFlags  flags)
13924 {
13925   ClutterActorPrivate *priv;
13926   ClutterActorBox allocation = { 0, };
13927   gfloat x_offset, y_offset;
13928   gfloat available_width, available_height;
13929   gfloat child_width, child_height;
13930
13931   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13932   g_return_if_fail (box != NULL);
13933   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13934   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13935
13936   priv = self->priv;
13937
13938   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13939   clutter_actor_box_get_size (box, &available_width, &available_height);
13940
13941   if (available_width < 0)
13942     available_width = 0;
13943
13944   if (available_height < 0)
13945     available_height = 0;
13946
13947   if (x_fill)
13948     {
13949       allocation.x1 = x_offset;
13950       allocation.x2 = allocation.x1 + available_width;
13951     }
13952
13953   if (y_fill)
13954     {
13955       allocation.y1 = y_offset;
13956       allocation.y2 = allocation.y1 + available_height;
13957     }
13958
13959   /* if we are filling horizontally and vertically then we're done */
13960   if (x_fill && y_fill)
13961     goto out;
13962
13963   child_width = child_height = 0.0f;
13964
13965   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13966     {
13967       gfloat min_width, natural_width;
13968       gfloat min_height, natural_height;
13969
13970       clutter_actor_get_preferred_width (self, available_height,
13971                                          &min_width,
13972                                          &natural_width);
13973
13974       child_width = CLAMP (natural_width, min_width, available_width);
13975
13976       if (!y_fill)
13977         {
13978           clutter_actor_get_preferred_height (self, child_width,
13979                                               &min_height,
13980                                               &natural_height);
13981
13982           child_height = CLAMP (natural_height, min_height, available_height);
13983         }
13984     }
13985   else
13986     {
13987       gfloat min_width, natural_width;
13988       gfloat min_height, natural_height;
13989
13990       clutter_actor_get_preferred_height (self, available_width,
13991                                           &min_height,
13992                                           &natural_height);
13993
13994       child_height = CLAMP (natural_height, min_height, available_height);
13995
13996       if (!x_fill)
13997         {
13998           clutter_actor_get_preferred_width (self, child_height,
13999                                              &min_width,
14000                                              &natural_width);
14001
14002           child_width = CLAMP (natural_width, min_width, available_width);
14003         }
14004     }
14005
14006   /* invert the horizontal alignment for RTL languages */
14007   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
14008     x_align = 1.0 - x_align;
14009
14010   if (!x_fill)
14011     {
14012       allocation.x1 = x_offset
14013                     + ((available_width - child_width) * x_align);
14014       allocation.x2 = allocation.x1 + child_width;
14015     }
14016
14017   if (!y_fill)
14018     {
14019       allocation.y1 = y_offset
14020                     + ((available_height - child_height) * y_align);
14021       allocation.y2 = allocation.y1 + child_height;
14022     }
14023
14024 out:
14025   clutter_actor_box_clamp_to_pixel (&allocation);
14026   clutter_actor_allocate (self, &allocation, flags);
14027 }
14028
14029 /**
14030  * clutter_actor_grab_key_focus:
14031  * @self: a #ClutterActor
14032  *
14033  * Sets the key focus of the #ClutterStage including @self
14034  * to this #ClutterActor.
14035  *
14036  * Since: 1.0
14037  */
14038 void
14039 clutter_actor_grab_key_focus (ClutterActor *self)
14040 {
14041   ClutterActor *stage;
14042
14043   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14044
14045   stage = _clutter_actor_get_stage_internal (self);
14046   if (stage != NULL)
14047     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
14048 }
14049
14050 /**
14051  * clutter_actor_get_pango_context:
14052  * @self: a #ClutterActor
14053  *
14054  * Retrieves the #PangoContext for @self. The actor's #PangoContext
14055  * is already configured using the appropriate font map, resolution
14056  * and font options.
14057  *
14058  * Unlike clutter_actor_create_pango_context(), this context is owend
14059  * by the #ClutterActor and it will be updated each time the options
14060  * stored by the #ClutterBackend change.
14061  *
14062  * You can use the returned #PangoContext to create a #PangoLayout
14063  * and render text using cogl_pango_render_layout() to reuse the
14064  * glyphs cache also used by Clutter.
14065  *
14066  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
14067  *   The returned #PangoContext is owned by the actor and should not be
14068  *   unreferenced by the application code
14069  *
14070  * Since: 1.0
14071  */
14072 PangoContext *
14073 clutter_actor_get_pango_context (ClutterActor *self)
14074 {
14075   ClutterActorPrivate *priv;
14076
14077   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14078
14079   priv = self->priv;
14080
14081   if (priv->pango_context != NULL)
14082     return priv->pango_context;
14083
14084   priv->pango_context = _clutter_context_get_pango_context ();
14085   g_object_ref (priv->pango_context);
14086
14087   return priv->pango_context;
14088 }
14089
14090 /**
14091  * clutter_actor_create_pango_context:
14092  * @self: a #ClutterActor
14093  *
14094  * Creates a #PangoContext for the given actor. The #PangoContext
14095  * is already configured using the appropriate font map, resolution
14096  * and font options.
14097  *
14098  * See also clutter_actor_get_pango_context().
14099  *
14100  * Return value: (transfer full): the newly created #PangoContext.
14101  *   Use g_object_unref() on the returned value to deallocate its
14102  *   resources
14103  *
14104  * Since: 1.0
14105  */
14106 PangoContext *
14107 clutter_actor_create_pango_context (ClutterActor *self)
14108 {
14109   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14110
14111   return _clutter_context_create_pango_context ();
14112 }
14113
14114 /**
14115  * clutter_actor_create_pango_layout:
14116  * @self: a #ClutterActor
14117  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14118  *
14119  * Creates a new #PangoLayout from the same #PangoContext used
14120  * by the #ClutterActor. The #PangoLayout is already configured
14121  * with the font map, resolution and font options, and the
14122  * given @text.
14123  *
14124  * If you want to keep around a #PangoLayout created by this
14125  * function you will have to connect to the #ClutterBackend::font-changed
14126  * and #ClutterBackend::resolution-changed signals, and call
14127  * pango_layout_context_changed() in response to them.
14128  *
14129  * Return value: (transfer full): the newly created #PangoLayout.
14130  *   Use g_object_unref() when done
14131  *
14132  * Since: 1.0
14133  */
14134 PangoLayout *
14135 clutter_actor_create_pango_layout (ClutterActor *self,
14136                                    const gchar  *text)
14137 {
14138   PangoContext *context;
14139   PangoLayout *layout;
14140
14141   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14142
14143   context = clutter_actor_get_pango_context (self);
14144   layout = pango_layout_new (context);
14145
14146   if (text)
14147     pango_layout_set_text (layout, text, -1);
14148
14149   return layout;
14150 }
14151
14152 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14153  * ClutterOffscreenEffect.
14154  */
14155 void
14156 _clutter_actor_set_opacity_override (ClutterActor *self,
14157                                      gint          opacity)
14158 {
14159   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14160
14161   self->priv->opacity_override = opacity;
14162 }
14163
14164 gint
14165 _clutter_actor_get_opacity_override (ClutterActor *self)
14166 {
14167   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14168
14169   return self->priv->opacity_override;
14170 }
14171
14172 /* Allows you to disable applying the actors model view transform during
14173  * a paint. Used by ClutterClone. */
14174 void
14175 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14176                                                 gboolean      enable)
14177 {
14178   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14179
14180   self->priv->enable_model_view_transform = enable;
14181 }
14182
14183 void
14184 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14185                                           gboolean      enable)
14186 {
14187   ClutterActorPrivate *priv;
14188
14189   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14190
14191   priv = self->priv;
14192
14193   priv->enable_paint_unmapped = enable;
14194
14195   if (priv->enable_paint_unmapped)
14196     {
14197       /* Make sure that the parents of the widget are realized first;
14198        * otherwise checks in clutter_actor_update_map_state() will
14199        * fail.
14200        */
14201       clutter_actor_realize (self);
14202
14203       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14204     }
14205   else
14206     {
14207       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14208     }
14209 }
14210
14211 static void
14212 clutter_anchor_coord_get_units (ClutterActor      *self,
14213                                 const AnchorCoord *coord,
14214                                 gfloat            *x,
14215                                 gfloat            *y,
14216                                 gfloat            *z)
14217 {
14218   if (coord->is_fractional)
14219     {
14220       gfloat actor_width, actor_height;
14221
14222       clutter_actor_get_size (self, &actor_width, &actor_height);
14223
14224       if (x)
14225         *x = actor_width * coord->v.fraction.x;
14226
14227       if (y)
14228         *y = actor_height * coord->v.fraction.y;
14229
14230       if (z)
14231         *z = 0;
14232     }
14233   else
14234     {
14235       if (x)
14236         *x = coord->v.units.x;
14237
14238       if (y)
14239         *y = coord->v.units.y;
14240
14241       if (z)
14242         *z = coord->v.units.z;
14243     }
14244 }
14245
14246 static void
14247 clutter_anchor_coord_set_units (AnchorCoord *coord,
14248                                 gfloat       x,
14249                                 gfloat       y,
14250                                 gfloat       z)
14251 {
14252   coord->is_fractional = FALSE;
14253   coord->v.units.x = x;
14254   coord->v.units.y = y;
14255   coord->v.units.z = z;
14256 }
14257
14258 static ClutterGravity
14259 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14260 {
14261   if (coord->is_fractional)
14262     {
14263       if (coord->v.fraction.x == 0.0)
14264         {
14265           if (coord->v.fraction.y == 0.0)
14266             return CLUTTER_GRAVITY_NORTH_WEST;
14267           else if (coord->v.fraction.y == 0.5)
14268             return CLUTTER_GRAVITY_WEST;
14269           else if (coord->v.fraction.y == 1.0)
14270             return CLUTTER_GRAVITY_SOUTH_WEST;
14271           else
14272             return CLUTTER_GRAVITY_NONE;
14273         }
14274       else if (coord->v.fraction.x == 0.5)
14275         {
14276           if (coord->v.fraction.y == 0.0)
14277             return CLUTTER_GRAVITY_NORTH;
14278           else if (coord->v.fraction.y == 0.5)
14279             return CLUTTER_GRAVITY_CENTER;
14280           else if (coord->v.fraction.y == 1.0)
14281             return CLUTTER_GRAVITY_SOUTH;
14282           else
14283             return CLUTTER_GRAVITY_NONE;
14284         }
14285       else if (coord->v.fraction.x == 1.0)
14286         {
14287           if (coord->v.fraction.y == 0.0)
14288             return CLUTTER_GRAVITY_NORTH_EAST;
14289           else if (coord->v.fraction.y == 0.5)
14290             return CLUTTER_GRAVITY_EAST;
14291           else if (coord->v.fraction.y == 1.0)
14292             return CLUTTER_GRAVITY_SOUTH_EAST;
14293           else
14294             return CLUTTER_GRAVITY_NONE;
14295         }
14296       else
14297         return CLUTTER_GRAVITY_NONE;
14298     }
14299   else
14300     return CLUTTER_GRAVITY_NONE;
14301 }
14302
14303 static void
14304 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14305                                   ClutterGravity  gravity)
14306 {
14307   switch (gravity)
14308     {
14309     case CLUTTER_GRAVITY_NORTH:
14310       coord->v.fraction.x = 0.5;
14311       coord->v.fraction.y = 0.0;
14312       break;
14313
14314     case CLUTTER_GRAVITY_NORTH_EAST:
14315       coord->v.fraction.x = 1.0;
14316       coord->v.fraction.y = 0.0;
14317       break;
14318
14319     case CLUTTER_GRAVITY_EAST:
14320       coord->v.fraction.x = 1.0;
14321       coord->v.fraction.y = 0.5;
14322       break;
14323
14324     case CLUTTER_GRAVITY_SOUTH_EAST:
14325       coord->v.fraction.x = 1.0;
14326       coord->v.fraction.y = 1.0;
14327       break;
14328
14329     case CLUTTER_GRAVITY_SOUTH:
14330       coord->v.fraction.x = 0.5;
14331       coord->v.fraction.y = 1.0;
14332       break;
14333
14334     case CLUTTER_GRAVITY_SOUTH_WEST:
14335       coord->v.fraction.x = 0.0;
14336       coord->v.fraction.y = 1.0;
14337       break;
14338
14339     case CLUTTER_GRAVITY_WEST:
14340       coord->v.fraction.x = 0.0;
14341       coord->v.fraction.y = 0.5;
14342       break;
14343
14344     case CLUTTER_GRAVITY_NORTH_WEST:
14345       coord->v.fraction.x = 0.0;
14346       coord->v.fraction.y = 0.0;
14347       break;
14348
14349     case CLUTTER_GRAVITY_CENTER:
14350       coord->v.fraction.x = 0.5;
14351       coord->v.fraction.y = 0.5;
14352       break;
14353
14354     default:
14355       coord->v.fraction.x = 0.0;
14356       coord->v.fraction.y = 0.0;
14357       break;
14358     }
14359
14360   coord->is_fractional = TRUE;
14361 }
14362
14363 static gboolean
14364 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14365 {
14366   if (coord->is_fractional)
14367     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14368   else
14369     return (coord->v.units.x == 0.0
14370             && coord->v.units.y == 0.0
14371             && coord->v.units.z == 0.0);
14372 }
14373
14374 /**
14375  * clutter_actor_get_flags:
14376  * @self: a #ClutterActor
14377  *
14378  * Retrieves the flags set on @self
14379  *
14380  * Return value: a bitwise or of #ClutterActorFlags or 0
14381  *
14382  * Since: 1.0
14383  */
14384 ClutterActorFlags
14385 clutter_actor_get_flags (ClutterActor *self)
14386 {
14387   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14388
14389   return self->flags;
14390 }
14391
14392 /**
14393  * clutter_actor_set_flags:
14394  * @self: a #ClutterActor
14395  * @flags: the flags to set
14396  *
14397  * Sets @flags on @self
14398  *
14399  * This function will emit notifications for the changed properties
14400  *
14401  * Since: 1.0
14402  */
14403 void
14404 clutter_actor_set_flags (ClutterActor      *self,
14405                          ClutterActorFlags  flags)
14406 {
14407   ClutterActorFlags old_flags;
14408   GObject *obj;
14409   gboolean was_reactive_set, reactive_set;
14410   gboolean was_realized_set, realized_set;
14411   gboolean was_mapped_set, mapped_set;
14412   gboolean was_visible_set, visible_set;
14413
14414   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14415
14416   if (self->flags == flags)
14417     return;
14418
14419   obj = G_OBJECT (self);
14420   g_object_ref (obj);
14421   g_object_freeze_notify (obj);
14422
14423   old_flags = self->flags;
14424
14425   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14426   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14427   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14428   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14429
14430   self->flags |= flags;
14431
14432   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14433   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14434   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14435   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14436
14437   if (reactive_set != was_reactive_set)
14438     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14439
14440   if (realized_set != was_realized_set)
14441     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14442
14443   if (mapped_set != was_mapped_set)
14444     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14445
14446   if (visible_set != was_visible_set)
14447     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14448
14449   g_object_thaw_notify (obj);
14450   g_object_unref (obj);
14451 }
14452
14453 /**
14454  * clutter_actor_unset_flags:
14455  * @self: a #ClutterActor
14456  * @flags: the flags to unset
14457  *
14458  * Unsets @flags on @self
14459  *
14460  * This function will emit notifications for the changed properties
14461  *
14462  * Since: 1.0
14463  */
14464 void
14465 clutter_actor_unset_flags (ClutterActor      *self,
14466                            ClutterActorFlags  flags)
14467 {
14468   ClutterActorFlags old_flags;
14469   GObject *obj;
14470   gboolean was_reactive_set, reactive_set;
14471   gboolean was_realized_set, realized_set;
14472   gboolean was_mapped_set, mapped_set;
14473   gboolean was_visible_set, visible_set;
14474
14475   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14476
14477   obj = G_OBJECT (self);
14478   g_object_freeze_notify (obj);
14479
14480   old_flags = self->flags;
14481
14482   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14483   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14484   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14485   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14486
14487   self->flags &= ~flags;
14488
14489   if (self->flags == old_flags)
14490     return;
14491
14492   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14493   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14494   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14495   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14496
14497   if (reactive_set != was_reactive_set)
14498     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14499
14500   if (realized_set != was_realized_set)
14501     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14502
14503   if (mapped_set != was_mapped_set)
14504     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14505
14506   if (visible_set != was_visible_set)
14507     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14508
14509   g_object_thaw_notify (obj);
14510 }
14511
14512 /**
14513  * clutter_actor_get_transformation_matrix:
14514  * @self: a #ClutterActor
14515  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14516  *
14517  * Retrieves the transformations applied to @self relative to its
14518  * parent.
14519  *
14520  * Since: 1.0
14521  */
14522 void
14523 clutter_actor_get_transformation_matrix (ClutterActor *self,
14524                                          CoglMatrix   *matrix)
14525 {
14526   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14527
14528   cogl_matrix_init_identity (matrix);
14529
14530   _clutter_actor_apply_modelview_transform (self, matrix);
14531 }
14532
14533 void
14534 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14535                                    gboolean      is_in_clone_paint)
14536 {
14537   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14538   self->priv->in_clone_paint = is_in_clone_paint;
14539 }
14540
14541 /**
14542  * clutter_actor_is_in_clone_paint:
14543  * @self: a #ClutterActor
14544  *
14545  * Checks whether @self is being currently painted by a #ClutterClone
14546  *
14547  * This function is useful only inside the ::paint virtual function
14548  * implementations or within handlers for the #ClutterActor::paint
14549  * signal
14550  *
14551  * This function should not be used by applications
14552  *
14553  * Return value: %TRUE if the #ClutterActor is currently being painted
14554  *   by a #ClutterClone, and %FALSE otherwise
14555  *
14556  * Since: 1.0
14557  */
14558 gboolean
14559 clutter_actor_is_in_clone_paint (ClutterActor *self)
14560 {
14561   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14562
14563   return self->priv->in_clone_paint;
14564 }
14565
14566 static gboolean
14567 set_direction_recursive (ClutterActor *actor,
14568                          gpointer      user_data)
14569 {
14570   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14571
14572   clutter_actor_set_text_direction (actor, text_dir);
14573
14574   return TRUE;
14575 }
14576
14577 /**
14578  * clutter_actor_set_text_direction:
14579  * @self: a #ClutterActor
14580  * @text_dir: the text direction for @self
14581  *
14582  * Sets the #ClutterTextDirection for an actor
14583  *
14584  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14585  *
14586  * If @self implements #ClutterContainer then this function will recurse
14587  * inside all the children of @self (including the internal ones).
14588  *
14589  * Composite actors not implementing #ClutterContainer, or actors requiring
14590  * special handling when the text direction changes, should connect to
14591  * the #GObject::notify signal for the #ClutterActor:text-direction property
14592  *
14593  * Since: 1.2
14594  */
14595 void
14596 clutter_actor_set_text_direction (ClutterActor         *self,
14597                                   ClutterTextDirection  text_dir)
14598 {
14599   ClutterActorPrivate *priv;
14600
14601   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14602   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14603
14604   priv = self->priv;
14605
14606   if (priv->text_direction != text_dir)
14607     {
14608       priv->text_direction = text_dir;
14609
14610       /* we need to emit the notify::text-direction first, so that
14611        * the sub-classes can catch that and do specific handling of
14612        * the text direction; see clutter_text_direction_changed_cb()
14613        * inside clutter-text.c
14614        */
14615       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14616
14617       _clutter_actor_foreach_child (self, set_direction_recursive,
14618                                     GINT_TO_POINTER (text_dir));
14619
14620       clutter_actor_queue_relayout (self);
14621     }
14622 }
14623
14624 void
14625 _clutter_actor_set_has_pointer (ClutterActor *self,
14626                                 gboolean      has_pointer)
14627 {
14628   ClutterActorPrivate *priv = self->priv;
14629
14630   if (priv->has_pointer != has_pointer)
14631     {
14632       priv->has_pointer = has_pointer;
14633
14634       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14635     }
14636 }
14637
14638 /**
14639  * clutter_actor_get_text_direction:
14640  * @self: a #ClutterActor
14641  *
14642  * Retrieves the value set using clutter_actor_set_text_direction()
14643  *
14644  * If no text direction has been previously set, the default text
14645  * direction, as returned by clutter_get_default_text_direction(), will
14646  * be returned instead
14647  *
14648  * Return value: the #ClutterTextDirection for the actor
14649  *
14650  * Since: 1.2
14651  */
14652 ClutterTextDirection
14653 clutter_actor_get_text_direction (ClutterActor *self)
14654 {
14655   ClutterActorPrivate *priv;
14656
14657   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14658                         CLUTTER_TEXT_DIRECTION_LTR);
14659
14660   priv = self->priv;
14661
14662   /* if no direction has been set yet use the default */
14663   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14664     priv->text_direction = clutter_get_default_text_direction ();
14665
14666   return priv->text_direction;
14667 }
14668
14669 /**
14670  * clutter_actor_push_internal:
14671  * @self: a #ClutterActor
14672  *
14673  * Should be used by actors implementing the #ClutterContainer and with
14674  * internal children added through clutter_actor_set_parent(), for instance:
14675  *
14676  * |[
14677  *   static void
14678  *   my_actor_init (MyActor *self)
14679  *   {
14680  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14681  *
14682  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14683  *
14684  *     /&ast; calling clutter_actor_set_parent() now will result in
14685  *      &ast; the internal flag being set on a child of MyActor
14686  *      &ast;/
14687  *
14688  *     /&ast; internal child - a background texture &ast;/
14689  *     self->priv->background_tex = clutter_texture_new ();
14690  *     clutter_actor_set_parent (self->priv->background_tex,
14691  *                               CLUTTER_ACTOR (self));
14692  *
14693  *     /&ast; internal child - a label &ast;/
14694  *     self->priv->label = clutter_text_new ();
14695  *     clutter_actor_set_parent (self->priv->label,
14696  *                               CLUTTER_ACTOR (self));
14697  *
14698  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14699  *
14700  *     /&ast; calling clutter_actor_set_parent() now will not result in
14701  *      &ast; the internal flag being set on a child of MyActor
14702  *      &ast;/
14703  *   }
14704  * ]|
14705  *
14706  * This function will be used by Clutter to toggle an "internal child"
14707  * flag whenever clutter_actor_set_parent() is called; internal children
14708  * are handled differently by Clutter, specifically when destroying their
14709  * parent.
14710  *
14711  * Call clutter_actor_pop_internal() when you finished adding internal
14712  * children.
14713  *
14714  * Nested calls to clutter_actor_push_internal() are allowed, but each
14715  * one must by followed by a clutter_actor_pop_internal() call.
14716  *
14717  * Since: 1.2
14718  *
14719  * Deprecated: 1.10: All children of an actor are accessible through
14720  *   the #ClutterActor API, and #ClutterActor implements the
14721  *   #ClutterContainer interface, so this function is only useful
14722  *   for legacy containers overriding the default implementation.
14723  */
14724 void
14725 clutter_actor_push_internal (ClutterActor *self)
14726 {
14727   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14728
14729   self->priv->internal_child += 1;
14730 }
14731
14732 /**
14733  * clutter_actor_pop_internal:
14734  * @self: a #ClutterActor
14735  *
14736  * Disables the effects of clutter_actor_push_internal().
14737  *
14738  * Since: 1.2
14739  *
14740  * Deprecated: 1.10: All children of an actor are accessible through
14741  *   the #ClutterActor API. This function is only useful for legacy
14742  *   containers overriding the default implementation of the
14743  *   #ClutterContainer interface.
14744  */
14745 void
14746 clutter_actor_pop_internal (ClutterActor *self)
14747 {
14748   ClutterActorPrivate *priv;
14749
14750   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14751
14752   priv = self->priv;
14753
14754   if (priv->internal_child == 0)
14755     {
14756       g_warning ("Mismatched %s: you need to call "
14757                  "clutter_actor_push_composite() at least once before "
14758                  "calling this function", G_STRFUNC);
14759       return;
14760     }
14761
14762   priv->internal_child -= 1;
14763 }
14764
14765 /**
14766  * clutter_actor_has_pointer:
14767  * @self: a #ClutterActor
14768  *
14769  * Checks whether an actor contains the pointer of a
14770  * #ClutterInputDevice
14771  *
14772  * Return value: %TRUE if the actor contains the pointer, and
14773  *   %FALSE otherwise
14774  *
14775  * Since: 1.2
14776  */
14777 gboolean
14778 clutter_actor_has_pointer (ClutterActor *self)
14779 {
14780   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14781
14782   return self->priv->has_pointer;
14783 }
14784
14785 /* XXX: This is a workaround for not being able to break the ABI of
14786  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14787  * clutter_actor_queue_clipped_redraw() for details.
14788  */
14789 ClutterPaintVolume *
14790 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14791 {
14792   return g_object_get_data (G_OBJECT (self),
14793                             "-clutter-actor-queue-redraw-clip");
14794 }
14795
14796 void
14797 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14798                                       ClutterPaintVolume *clip)
14799 {
14800   g_object_set_data (G_OBJECT (self),
14801                      "-clutter-actor-queue-redraw-clip",
14802                      clip);
14803 }
14804
14805 /**
14806  * clutter_actor_has_allocation:
14807  * @self: a #ClutterActor
14808  *
14809  * Checks if the actor has an up-to-date allocation assigned to
14810  * it. This means that the actor should have an allocation: it's
14811  * visible and has a parent. It also means that there is no
14812  * outstanding relayout request in progress for the actor or its
14813  * children (There might be other outstanding layout requests in
14814  * progress that will cause the actor to get a new allocation
14815  * when the stage is laid out, however).
14816  *
14817  * If this function returns %FALSE, then the actor will normally
14818  * be allocated before it is next drawn on the screen.
14819  *
14820  * Return value: %TRUE if the actor has an up-to-date allocation
14821  *
14822  * Since: 1.4
14823  */
14824 gboolean
14825 clutter_actor_has_allocation (ClutterActor *self)
14826 {
14827   ClutterActorPrivate *priv;
14828
14829   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14830
14831   priv = self->priv;
14832
14833   return priv->parent != NULL &&
14834          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14835          !priv->needs_allocation;
14836 }
14837
14838 /**
14839  * clutter_actor_add_action:
14840  * @self: a #ClutterActor
14841  * @action: a #ClutterAction
14842  *
14843  * Adds @action to the list of actions applied to @self
14844  *
14845  * A #ClutterAction can only belong to one actor at a time
14846  *
14847  * The #ClutterActor will hold a reference on @action until either
14848  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14849  * is called
14850  *
14851  * Since: 1.4
14852  */
14853 void
14854 clutter_actor_add_action (ClutterActor  *self,
14855                           ClutterAction *action)
14856 {
14857   ClutterActorPrivate *priv;
14858
14859   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14860   g_return_if_fail (CLUTTER_IS_ACTION (action));
14861
14862   priv = self->priv;
14863
14864   if (priv->actions == NULL)
14865     {
14866       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14867       priv->actions->actor = self;
14868     }
14869
14870   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14871
14872   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14873 }
14874
14875 /**
14876  * clutter_actor_add_action_with_name:
14877  * @self: a #ClutterActor
14878  * @name: the name to set on the action
14879  * @action: a #ClutterAction
14880  *
14881  * A convenience function for setting the name of a #ClutterAction
14882  * while adding it to the list of actions applied to @self
14883  *
14884  * This function is the logical equivalent of:
14885  *
14886  * |[
14887  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14888  *   clutter_actor_add_action (self, action);
14889  * ]|
14890  *
14891  * Since: 1.4
14892  */
14893 void
14894 clutter_actor_add_action_with_name (ClutterActor  *self,
14895                                     const gchar   *name,
14896                                     ClutterAction *action)
14897 {
14898   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14899   g_return_if_fail (name != NULL);
14900   g_return_if_fail (CLUTTER_IS_ACTION (action));
14901
14902   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14903   clutter_actor_add_action (self, action);
14904 }
14905
14906 /**
14907  * clutter_actor_remove_action:
14908  * @self: a #ClutterActor
14909  * @action: a #ClutterAction
14910  *
14911  * Removes @action from the list of actions applied to @self
14912  *
14913  * The reference held by @self on the #ClutterAction will be released
14914  *
14915  * Since: 1.4
14916  */
14917 void
14918 clutter_actor_remove_action (ClutterActor  *self,
14919                              ClutterAction *action)
14920 {
14921   ClutterActorPrivate *priv;
14922
14923   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14924   g_return_if_fail (CLUTTER_IS_ACTION (action));
14925
14926   priv = self->priv;
14927
14928   if (priv->actions == NULL)
14929     return;
14930
14931   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14932
14933   if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
14934     g_clear_object (&priv->actions);
14935
14936   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14937 }
14938
14939 /**
14940  * clutter_actor_remove_action_by_name:
14941  * @self: a #ClutterActor
14942  * @name: the name of the action to remove
14943  *
14944  * Removes the #ClutterAction with the given name from the list
14945  * of actions applied to @self
14946  *
14947  * Since: 1.4
14948  */
14949 void
14950 clutter_actor_remove_action_by_name (ClutterActor *self,
14951                                      const gchar  *name)
14952 {
14953   ClutterActorPrivate *priv;
14954   ClutterActorMeta *meta;
14955
14956   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14957   g_return_if_fail (name != NULL);
14958
14959   priv = self->priv;
14960
14961   if (priv->actions == NULL)
14962     return;
14963
14964   meta = _clutter_meta_group_get_meta (priv->actions, name);
14965   if (meta == NULL)
14966     return;
14967
14968   _clutter_meta_group_remove_meta (priv->actions, meta);
14969
14970   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14971 }
14972
14973 /**
14974  * clutter_actor_get_actions:
14975  * @self: a #ClutterActor
14976  *
14977  * Retrieves the list of actions applied to @self
14978  *
14979  * Return value: (transfer container) (element-type Clutter.Action): a copy
14980  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14981  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14982  *   allocated by the returned #GList
14983  *
14984  * Since: 1.4
14985  */
14986 GList *
14987 clutter_actor_get_actions (ClutterActor *self)
14988 {
14989   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14990
14991   if (self->priv->actions == NULL)
14992     return NULL;
14993
14994   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14995 }
14996
14997 /**
14998  * clutter_actor_get_action:
14999  * @self: a #ClutterActor
15000  * @name: the name of the action to retrieve
15001  *
15002  * Retrieves the #ClutterAction with the given name in the list
15003  * of actions applied to @self
15004  *
15005  * Return value: (transfer none): a #ClutterAction for the given
15006  *   name, or %NULL. The returned #ClutterAction is owned by the
15007  *   actor and it should not be unreferenced directly
15008  *
15009  * Since: 1.4
15010  */
15011 ClutterAction *
15012 clutter_actor_get_action (ClutterActor *self,
15013                           const gchar  *name)
15014 {
15015   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15016   g_return_val_if_fail (name != NULL, NULL);
15017
15018   if (self->priv->actions == NULL)
15019     return NULL;
15020
15021   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
15022 }
15023
15024 /**
15025  * clutter_actor_clear_actions:
15026  * @self: a #ClutterActor
15027  *
15028  * Clears the list of actions applied to @self
15029  *
15030  * Since: 1.4
15031  */
15032 void
15033 clutter_actor_clear_actions (ClutterActor *self)
15034 {
15035   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15036
15037   if (self->priv->actions == NULL)
15038     return;
15039
15040   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
15041 }
15042
15043 /**
15044  * clutter_actor_add_constraint:
15045  * @self: a #ClutterActor
15046  * @constraint: a #ClutterConstraint
15047  *
15048  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
15049  * to @self
15050  *
15051  * The #ClutterActor will hold a reference on the @constraint until
15052  * either clutter_actor_remove_constraint() or
15053  * clutter_actor_clear_constraints() is called.
15054  *
15055  * Since: 1.4
15056  */
15057 void
15058 clutter_actor_add_constraint (ClutterActor      *self,
15059                               ClutterConstraint *constraint)
15060 {
15061   ClutterActorPrivate *priv;
15062
15063   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15064   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15065
15066   priv = self->priv;
15067
15068   if (priv->constraints == NULL)
15069     {
15070       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15071       priv->constraints->actor = self;
15072     }
15073
15074   _clutter_meta_group_add_meta (priv->constraints,
15075                                 CLUTTER_ACTOR_META (constraint));
15076   clutter_actor_queue_relayout (self);
15077
15078   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15079 }
15080
15081 /**
15082  * clutter_actor_add_constraint_with_name:
15083  * @self: a #ClutterActor
15084  * @name: the name to set on the constraint
15085  * @constraint: a #ClutterConstraint
15086  *
15087  * A convenience function for setting the name of a #ClutterConstraint
15088  * while adding it to the list of constraints applied to @self
15089  *
15090  * This function is the logical equivalent of:
15091  *
15092  * |[
15093  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15094  *   clutter_actor_add_constraint (self, constraint);
15095  * ]|
15096  *
15097  * Since: 1.4
15098  */
15099 void
15100 clutter_actor_add_constraint_with_name (ClutterActor      *self,
15101                                         const gchar       *name,
15102                                         ClutterConstraint *constraint)
15103 {
15104   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15105   g_return_if_fail (name != NULL);
15106   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15107
15108   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15109   clutter_actor_add_constraint (self, constraint);
15110 }
15111
15112 /**
15113  * clutter_actor_remove_constraint:
15114  * @self: a #ClutterActor
15115  * @constraint: a #ClutterConstraint
15116  *
15117  * Removes @constraint from the list of constraints applied to @self
15118  *
15119  * The reference held by @self on the #ClutterConstraint will be released
15120  *
15121  * Since: 1.4
15122  */
15123 void
15124 clutter_actor_remove_constraint (ClutterActor      *self,
15125                                  ClutterConstraint *constraint)
15126 {
15127   ClutterActorPrivate *priv;
15128
15129   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15130   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15131
15132   priv = self->priv;
15133
15134   if (priv->constraints == NULL)
15135     return;
15136
15137   _clutter_meta_group_remove_meta (priv->constraints,
15138                                    CLUTTER_ACTOR_META (constraint));
15139
15140   if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15141     g_clear_object (&priv->constraints);
15142
15143   clutter_actor_queue_relayout (self);
15144
15145   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15146 }
15147
15148 /**
15149  * clutter_actor_remove_constraint_by_name:
15150  * @self: a #ClutterActor
15151  * @name: the name of the constraint to remove
15152  *
15153  * Removes the #ClutterConstraint with the given name from the list
15154  * of constraints applied to @self
15155  *
15156  * Since: 1.4
15157  */
15158 void
15159 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15160                                          const gchar  *name)
15161 {
15162   ClutterActorPrivate *priv;
15163   ClutterActorMeta *meta;
15164
15165   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15166   g_return_if_fail (name != NULL);
15167
15168   priv = self->priv;
15169
15170   if (priv->constraints == NULL)
15171     return;
15172
15173   meta = _clutter_meta_group_get_meta (priv->constraints, name);
15174   if (meta == NULL)
15175     return;
15176
15177   _clutter_meta_group_remove_meta (priv->constraints, meta);
15178   clutter_actor_queue_relayout (self);
15179 }
15180
15181 /**
15182  * clutter_actor_get_constraints:
15183  * @self: a #ClutterActor
15184  *
15185  * Retrieves the list of constraints applied to @self
15186  *
15187  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15188  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15189  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15190  *   allocated by the returned #GList
15191  *
15192  * Since: 1.4
15193  */
15194 GList *
15195 clutter_actor_get_constraints (ClutterActor *self)
15196 {
15197   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15198
15199   if (self->priv->constraints == NULL)
15200     return NULL;
15201
15202   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15203 }
15204
15205 /**
15206  * clutter_actor_get_constraint:
15207  * @self: a #ClutterActor
15208  * @name: the name of the constraint to retrieve
15209  *
15210  * Retrieves the #ClutterConstraint with the given name in the list
15211  * of constraints applied to @self
15212  *
15213  * Return value: (transfer none): a #ClutterConstraint for the given
15214  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15215  *   actor and it should not be unreferenced directly
15216  *
15217  * Since: 1.4
15218  */
15219 ClutterConstraint *
15220 clutter_actor_get_constraint (ClutterActor *self,
15221                               const gchar  *name)
15222 {
15223   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15224   g_return_val_if_fail (name != NULL, NULL);
15225
15226   if (self->priv->constraints == NULL)
15227     return NULL;
15228
15229   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15230 }
15231
15232 /**
15233  * clutter_actor_clear_constraints:
15234  * @self: a #ClutterActor
15235  *
15236  * Clears the list of constraints applied to @self
15237  *
15238  * Since: 1.4
15239  */
15240 void
15241 clutter_actor_clear_constraints (ClutterActor *self)
15242 {
15243   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15244
15245   if (self->priv->constraints == NULL)
15246     return;
15247
15248   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15249
15250   clutter_actor_queue_relayout (self);
15251 }
15252
15253 /**
15254  * clutter_actor_set_clip_to_allocation:
15255  * @self: a #ClutterActor
15256  * @clip_set: %TRUE to apply a clip tracking the allocation
15257  *
15258  * Sets whether @self should be clipped to the same size as its
15259  * allocation
15260  *
15261  * Since: 1.4
15262  */
15263 void
15264 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15265                                       gboolean      clip_set)
15266 {
15267   ClutterActorPrivate *priv;
15268
15269   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15270
15271   clip_set = !!clip_set;
15272
15273   priv = self->priv;
15274
15275   if (priv->clip_to_allocation != clip_set)
15276     {
15277       priv->clip_to_allocation = clip_set;
15278
15279       clutter_actor_queue_redraw (self);
15280
15281       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15282     }
15283 }
15284
15285 /**
15286  * clutter_actor_get_clip_to_allocation:
15287  * @self: a #ClutterActor
15288  *
15289  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15290  *
15291  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15292  *
15293  * Since: 1.4
15294  */
15295 gboolean
15296 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15297 {
15298   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15299
15300   return self->priv->clip_to_allocation;
15301 }
15302
15303 /**
15304  * clutter_actor_add_effect:
15305  * @self: a #ClutterActor
15306  * @effect: a #ClutterEffect
15307  *
15308  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15309  *
15310  * The #ClutterActor will hold a reference on the @effect until either
15311  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15312  * called.
15313  *
15314  * Since: 1.4
15315  */
15316 void
15317 clutter_actor_add_effect (ClutterActor  *self,
15318                           ClutterEffect *effect)
15319 {
15320   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15321   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15322
15323   _clutter_actor_add_effect_internal (self, effect);
15324
15325   clutter_actor_queue_redraw (self);
15326
15327   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15328 }
15329
15330 /**
15331  * clutter_actor_add_effect_with_name:
15332  * @self: a #ClutterActor
15333  * @name: the name to set on the effect
15334  * @effect: a #ClutterEffect
15335  *
15336  * A convenience function for setting the name of a #ClutterEffect
15337  * while adding it to the list of effectss applied to @self
15338  *
15339  * This function is the logical equivalent of:
15340  *
15341  * |[
15342  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15343  *   clutter_actor_add_effect (self, effect);
15344  * ]|
15345  *
15346  * Since: 1.4
15347  */
15348 void
15349 clutter_actor_add_effect_with_name (ClutterActor  *self,
15350                                     const gchar   *name,
15351                                     ClutterEffect *effect)
15352 {
15353   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15354   g_return_if_fail (name != NULL);
15355   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15356
15357   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15358   clutter_actor_add_effect (self, effect);
15359 }
15360
15361 /**
15362  * clutter_actor_remove_effect:
15363  * @self: a #ClutterActor
15364  * @effect: a #ClutterEffect
15365  *
15366  * Removes @effect from the list of effects applied to @self
15367  *
15368  * The reference held by @self on the #ClutterEffect will be released
15369  *
15370  * Since: 1.4
15371  */
15372 void
15373 clutter_actor_remove_effect (ClutterActor  *self,
15374                              ClutterEffect *effect)
15375 {
15376   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15377   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15378
15379   _clutter_actor_remove_effect_internal (self, effect);
15380
15381   clutter_actor_queue_redraw (self);
15382
15383   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15384 }
15385
15386 /**
15387  * clutter_actor_remove_effect_by_name:
15388  * @self: a #ClutterActor
15389  * @name: the name of the effect to remove
15390  *
15391  * Removes the #ClutterEffect with the given name from the list
15392  * of effects applied to @self
15393  *
15394  * Since: 1.4
15395  */
15396 void
15397 clutter_actor_remove_effect_by_name (ClutterActor *self,
15398                                      const gchar  *name)
15399 {
15400   ClutterActorPrivate *priv;
15401   ClutterActorMeta *meta;
15402
15403   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15404   g_return_if_fail (name != NULL);
15405
15406   priv = self->priv;
15407
15408   if (priv->effects == NULL)
15409     return;
15410
15411   meta = _clutter_meta_group_get_meta (priv->effects, name);
15412   if (meta == NULL)
15413     return;
15414
15415   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15416 }
15417
15418 /**
15419  * clutter_actor_get_effects:
15420  * @self: a #ClutterActor
15421  *
15422  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15423  *
15424  * Return value: (transfer container) (element-type Clutter.Effect): a list
15425  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15426  *   list are owned by Clutter and they should not be freed. You should
15427  *   free the returned list using g_list_free() when done
15428  *
15429  * Since: 1.4
15430  */
15431 GList *
15432 clutter_actor_get_effects (ClutterActor *self)
15433 {
15434   ClutterActorPrivate *priv;
15435
15436   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15437
15438   priv = self->priv;
15439
15440   if (priv->effects == NULL)
15441     return NULL;
15442
15443   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15444 }
15445
15446 /**
15447  * clutter_actor_get_effect:
15448  * @self: a #ClutterActor
15449  * @name: the name of the effect to retrieve
15450  *
15451  * Retrieves the #ClutterEffect with the given name in the list
15452  * of effects applied to @self
15453  *
15454  * Return value: (transfer none): a #ClutterEffect for the given
15455  *   name, or %NULL. The returned #ClutterEffect is owned by the
15456  *   actor and it should not be unreferenced directly
15457  *
15458  * Since: 1.4
15459  */
15460 ClutterEffect *
15461 clutter_actor_get_effect (ClutterActor *self,
15462                           const gchar  *name)
15463 {
15464   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15465   g_return_val_if_fail (name != NULL, NULL);
15466
15467   if (self->priv->effects == NULL)
15468     return NULL;
15469
15470   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15471 }
15472
15473 /**
15474  * clutter_actor_clear_effects:
15475  * @self: a #ClutterActor
15476  *
15477  * Clears the list of effects applied to @self
15478  *
15479  * Since: 1.4
15480  */
15481 void
15482 clutter_actor_clear_effects (ClutterActor *self)
15483 {
15484   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15485
15486   if (self->priv->effects == NULL)
15487     return;
15488
15489   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15490
15491   clutter_actor_queue_redraw (self);
15492 }
15493
15494 /**
15495  * clutter_actor_has_key_focus:
15496  * @self: a #ClutterActor
15497  *
15498  * Checks whether @self is the #ClutterActor that has key focus
15499  *
15500  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15501  *
15502  * Since: 1.4
15503  */
15504 gboolean
15505 clutter_actor_has_key_focus (ClutterActor *self)
15506 {
15507   ClutterActor *stage;
15508
15509   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15510
15511   stage = _clutter_actor_get_stage_internal (self);
15512   if (stage == NULL)
15513     return FALSE;
15514
15515   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15516 }
15517
15518 static gboolean
15519 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15520                                       ClutterPaintVolume *pv)
15521 {
15522   ClutterActorPrivate *priv = self->priv;
15523
15524   /* Actors are only expected to report a valid paint volume
15525    * while they have a valid allocation. */
15526   if (G_UNLIKELY (priv->needs_allocation))
15527     {
15528       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15529                     "Actor needs allocation",
15530                     _clutter_actor_get_debug_name (self));
15531       return FALSE;
15532     }
15533
15534   /* Check if there are any handlers connected to the paint
15535    * signal. If there are then all bets are off for what the paint
15536    * volume for this actor might possibly be!
15537    *
15538    * XXX: It's expected that this is going to end up being quite a
15539    * costly check to have to do here, but we haven't come up with
15540    * another solution that can reliably catch paint signal handlers at
15541    * the right time to either avoid artefacts due to invalid stage
15542    * clipping or due to incorrect culling.
15543    *
15544    * Previously we checked in clutter_actor_paint(), but at that time
15545    * we may already be using a stage clip that could be derived from
15546    * an invalid paint-volume. We used to try and handle that by
15547    * queuing a follow up, unclipped, redraw but still the previous
15548    * checking wasn't enough to catch invalid volumes involved in
15549    * culling (considering that containers may derive their volume from
15550    * children that haven't yet been painted)
15551    *
15552    * Longer term, improved solutions could be:
15553    * - Disallow painting in the paint signal, only allow using it
15554    *   for tracking when paints happen. We can add another API that
15555    *   allows monkey patching the paint of arbitrary actors but in a
15556    *   more controlled way and that also supports modifying the
15557    *   paint-volume.
15558    * - If we could be notified somehow when signal handlers are
15559    *   connected we wouldn't have to poll for handlers like this.
15560    */
15561   if (g_signal_has_handler_pending (self,
15562                                     actor_signals[PAINT],
15563                                     0,
15564                                     TRUE))
15565     {
15566       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15567                     "Actor has \"paint\" signal handlers",
15568                     _clutter_actor_get_debug_name (self));
15569       return FALSE;
15570     }
15571
15572   _clutter_paint_volume_init_static (pv, self);
15573
15574   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15575     {
15576       clutter_paint_volume_free (pv);
15577       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15578                     "Actor failed to report a volume",
15579                     _clutter_actor_get_debug_name (self));
15580       return FALSE;
15581     }
15582
15583   /* since effects can modify the paint volume, we allow them to actually
15584    * do this by making get_paint_volume() "context sensitive"
15585    */
15586   if (priv->effects != NULL)
15587     {
15588       if (priv->current_effect != NULL)
15589         {
15590           const GList *effects, *l;
15591
15592           /* if we are being called from within the paint sequence of
15593            * an actor, get the paint volume up to the current effect
15594            */
15595           effects = _clutter_meta_group_peek_metas (priv->effects);
15596           for (l = effects;
15597                l != NULL || (l != NULL && l->data != priv->current_effect);
15598                l = l->next)
15599             {
15600               if (!_clutter_effect_get_paint_volume (l->data, pv))
15601                 {
15602                   clutter_paint_volume_free (pv);
15603                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15604                                 "Effect (%s) failed to report a volume",
15605                                 _clutter_actor_get_debug_name (self),
15606                                 _clutter_actor_meta_get_debug_name (l->data));
15607                   return FALSE;
15608                 }
15609             }
15610         }
15611       else
15612         {
15613           const GList *effects, *l;
15614
15615           /* otherwise, get the cumulative volume */
15616           effects = _clutter_meta_group_peek_metas (priv->effects);
15617           for (l = effects; l != NULL; l = l->next)
15618             if (!_clutter_effect_get_paint_volume (l->data, pv))
15619               {
15620                 clutter_paint_volume_free (pv);
15621                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15622                               "Effect (%s) failed to report a volume",
15623                               _clutter_actor_get_debug_name (self),
15624                               _clutter_actor_meta_get_debug_name (l->data));
15625                 return FALSE;
15626               }
15627         }
15628     }
15629
15630   return TRUE;
15631 }
15632
15633 /* The public clutter_actor_get_paint_volume API returns a const
15634  * pointer since we return a pointer directly to the cached
15635  * PaintVolume associated with the actor and don't want the user to
15636  * inadvertently modify it, but for internal uses we sometimes need
15637  * access to the same PaintVolume but need to apply some book-keeping
15638  * modifications to it so we don't want a const pointer.
15639  */
15640 static ClutterPaintVolume *
15641 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15642 {
15643   ClutterActorPrivate *priv;
15644
15645   priv = self->priv;
15646
15647   if (priv->paint_volume_valid)
15648     clutter_paint_volume_free (&priv->paint_volume);
15649
15650   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15651     {
15652       priv->paint_volume_valid = TRUE;
15653       return &priv->paint_volume;
15654     }
15655   else
15656     {
15657       priv->paint_volume_valid = FALSE;
15658       return NULL;
15659     }
15660 }
15661
15662 /**
15663  * clutter_actor_get_paint_volume:
15664  * @self: a #ClutterActor
15665  *
15666  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15667  * when a paint volume can't be determined.
15668  *
15669  * The paint volume is defined as the 3D space occupied by an actor
15670  * when being painted.
15671  *
15672  * This function will call the <function>get_paint_volume()</function>
15673  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15674  * should not usually care about overriding the default implementation,
15675  * unless they are, for instance: painting outside their allocation, or
15676  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15677  * 3D depth).
15678  *
15679  * <note>2D actors overriding <function>get_paint_volume()</function>
15680  * ensure their volume has a depth of 0. (This will be true so long as
15681  * you don't call clutter_paint_volume_set_depth().)</note>
15682  *
15683  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15684  *   or %NULL if no volume could be determined. The returned pointer
15685  *   is not guaranteed to be valid across multiple frames; if you want
15686  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15687  *
15688  * Since: 1.6
15689  */
15690 const ClutterPaintVolume *
15691 clutter_actor_get_paint_volume (ClutterActor *self)
15692 {
15693   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15694
15695   return _clutter_actor_get_paint_volume_mutable (self);
15696 }
15697
15698 /**
15699  * clutter_actor_get_transformed_paint_volume:
15700  * @self: a #ClutterActor
15701  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15702  *    (or %NULL for the stage)
15703  *
15704  * Retrieves the 3D paint volume of an actor like
15705  * clutter_actor_get_paint_volume() does (Please refer to the
15706  * documentation of clutter_actor_get_paint_volume() for more
15707  * details.) and it additionally transforms the paint volume into the
15708  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15709  * is passed for @relative_to_ancestor)
15710  *
15711  * This can be used by containers that base their paint volume on
15712  * the volume of their children. Such containers can query the
15713  * transformed paint volume of all of its children and union them
15714  * together using clutter_paint_volume_union().
15715  *
15716  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15717  *   or %NULL if no volume could be determined. The returned pointer is
15718  *   not guaranteed to be valid across multiple frames; if you wish to
15719  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15720  *
15721  * Since: 1.6
15722  */
15723 const ClutterPaintVolume *
15724 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15725                                             ClutterActor *relative_to_ancestor)
15726 {
15727   const ClutterPaintVolume *volume;
15728   ClutterActor *stage;
15729   ClutterPaintVolume *transformed_volume;
15730
15731   stage = _clutter_actor_get_stage_internal (self);
15732   if (G_UNLIKELY (stage == NULL))
15733     return NULL;
15734
15735   if (relative_to_ancestor == NULL)
15736     relative_to_ancestor = stage;
15737
15738   volume = clutter_actor_get_paint_volume (self);
15739   if (volume == NULL)
15740     return NULL;
15741
15742   transformed_volume =
15743     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15744
15745   _clutter_paint_volume_copy_static (volume, transformed_volume);
15746
15747   _clutter_paint_volume_transform_relative (transformed_volume,
15748                                             relative_to_ancestor);
15749
15750   return transformed_volume;
15751 }
15752
15753 /**
15754  * clutter_actor_get_paint_box:
15755  * @self: a #ClutterActor
15756  * @box: (out): return location for a #ClutterActorBox
15757  *
15758  * Retrieves the paint volume of the passed #ClutterActor, and
15759  * transforms it into a 2D bounding box in stage coordinates.
15760  *
15761  * This function is useful to determine the on screen area occupied by
15762  * the actor. The box is only an approximation and may often be
15763  * considerably larger due to the optimizations used to calculate the
15764  * box. The box is never smaller though, so it can reliably be used
15765  * for culling.
15766  *
15767  * There are times when a 2D paint box can't be determined, e.g.
15768  * because the actor isn't yet parented under a stage or because
15769  * the actor is unable to determine a paint volume.
15770  *
15771  * Return value: %TRUE if a 2D paint box could be determined, else
15772  * %FALSE.
15773  *
15774  * Since: 1.6
15775  */
15776 gboolean
15777 clutter_actor_get_paint_box (ClutterActor    *self,
15778                              ClutterActorBox *box)
15779 {
15780   ClutterActor *stage;
15781   ClutterPaintVolume *pv;
15782
15783   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15784   g_return_val_if_fail (box != NULL, FALSE);
15785
15786   stage = _clutter_actor_get_stage_internal (self);
15787   if (G_UNLIKELY (!stage))
15788     return FALSE;
15789
15790   pv = _clutter_actor_get_paint_volume_mutable (self);
15791   if (G_UNLIKELY (!pv))
15792     return FALSE;
15793
15794   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15795
15796   return TRUE;
15797 }
15798
15799 /**
15800  * clutter_actor_has_overlaps:
15801  * @self: A #ClutterActor
15802  *
15803  * Asks the actor's implementation whether it may contain overlapping
15804  * primitives.
15805  *
15806  * For example; Clutter may use this to determine whether the painting
15807  * should be redirected to an offscreen buffer to correctly implement
15808  * the opacity property.
15809  *
15810  * Custom actors can override the default response by implementing the
15811  * #ClutterActor <function>has_overlaps</function> virtual function. See
15812  * clutter_actor_set_offscreen_redirect() for more information.
15813  *
15814  * Return value: %TRUE if the actor may have overlapping primitives, and
15815  *   %FALSE otherwise
15816  *
15817  * Since: 1.8
15818  */
15819 gboolean
15820 clutter_actor_has_overlaps (ClutterActor *self)
15821 {
15822   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15823
15824   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15825 }
15826
15827 /**
15828  * clutter_actor_has_effects:
15829  * @self: A #ClutterActor
15830  *
15831  * Returns whether the actor has any effects applied.
15832  *
15833  * Return value: %TRUE if the actor has any effects,
15834  *   %FALSE otherwise
15835  *
15836  * Since: 1.10
15837  */
15838 gboolean
15839 clutter_actor_has_effects (ClutterActor *self)
15840 {
15841   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15842
15843   if (self->priv->effects == NULL)
15844     return FALSE;
15845
15846   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15847 }
15848
15849 /**
15850  * clutter_actor_has_constraints:
15851  * @self: A #ClutterActor
15852  *
15853  * Returns whether the actor has any constraints applied.
15854  *
15855  * Return value: %TRUE if the actor has any constraints,
15856  *   %FALSE otherwise
15857  *
15858  * Since: 1.10
15859  */
15860 gboolean
15861 clutter_actor_has_constraints (ClutterActor *self)
15862 {
15863   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15864
15865   return self->priv->constraints != NULL;
15866 }
15867
15868 /**
15869  * clutter_actor_has_actions:
15870  * @self: A #ClutterActor
15871  *
15872  * Returns whether the actor has any actions applied.
15873  *
15874  * Return value: %TRUE if the actor has any actions,
15875  *   %FALSE otherwise
15876  *
15877  * Since: 1.10
15878  */
15879 gboolean
15880 clutter_actor_has_actions (ClutterActor *self)
15881 {
15882   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15883
15884   return self->priv->actions != NULL;
15885 }
15886
15887 /**
15888  * clutter_actor_get_n_children:
15889  * @self: a #ClutterActor
15890  *
15891  * Retrieves the number of children of @self.
15892  *
15893  * Return value: the number of children of an actor
15894  *
15895  * Since: 1.10
15896  */
15897 gint
15898 clutter_actor_get_n_children (ClutterActor *self)
15899 {
15900   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15901
15902   return self->priv->n_children;
15903 }
15904
15905 /**
15906  * clutter_actor_get_child_at_index:
15907  * @self: a #ClutterActor
15908  * @index_: the position in the list of children
15909  *
15910  * Retrieves the actor at the given @index_ inside the list of
15911  * children of @self.
15912  *
15913  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15914  *
15915  * Since: 1.10
15916  */
15917 ClutterActor *
15918 clutter_actor_get_child_at_index (ClutterActor *self,
15919                                   gint          index_)
15920 {
15921   ClutterActor *iter;
15922   int i;
15923
15924   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15925   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15926
15927   for (iter = self->priv->first_child, i = 0;
15928        iter != NULL && i < index_;
15929        iter = iter->priv->next_sibling, i += 1)
15930     ;
15931
15932   return iter;
15933 }
15934
15935 /*< private >
15936  * _clutter_actor_foreach_child:
15937  * @actor: The actor whos children you want to iterate
15938  * @callback: The function to call for each child
15939  * @user_data: Private data to pass to @callback
15940  *
15941  * Calls a given @callback once for each child of the specified @actor and
15942  * passing the @user_data pointer each time.
15943  *
15944  * Return value: returns %TRUE if all children were iterated, else
15945  *    %FALSE if a callback broke out of iteration early.
15946  */
15947 gboolean
15948 _clutter_actor_foreach_child (ClutterActor           *self,
15949                               ClutterForeachCallback  callback,
15950                               gpointer                user_data)
15951 {
15952   ClutterActor *iter;
15953   gboolean cont;
15954
15955   if (self->priv->first_child == NULL)
15956     return TRUE;
15957
15958   cont = TRUE;
15959   iter = self->priv->first_child;
15960
15961   /* we use this form so that it's safe to change the children
15962    * list while iterating it
15963    */
15964   while (cont && iter != NULL)
15965     {
15966       ClutterActor *next = iter->priv->next_sibling;
15967
15968       cont = callback (iter, user_data);
15969
15970       iter = next;
15971     }
15972
15973   return cont;
15974 }
15975
15976 #if 0
15977 /* For debugging purposes this gives us a simple way to print out
15978  * the scenegraph e.g in gdb using:
15979  * [|
15980  *   _clutter_actor_traverse (stage,
15981  *                            0,
15982  *                            clutter_debug_print_actor_cb,
15983  *                            NULL,
15984  *                            NULL);
15985  * |]
15986  */
15987 static ClutterActorTraverseVisitFlags
15988 clutter_debug_print_actor_cb (ClutterActor *actor,
15989                               int depth,
15990                               void *user_data)
15991 {
15992   g_print ("%*s%s:%p\n",
15993            depth * 2, "",
15994            _clutter_actor_get_debug_name (actor),
15995            actor);
15996
15997   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15998 }
15999 #endif
16000
16001 static void
16002 _clutter_actor_traverse_breadth (ClutterActor           *actor,
16003                                  ClutterTraverseCallback callback,
16004                                  gpointer                user_data)
16005 {
16006   GQueue *queue = g_queue_new ();
16007   ClutterActor dummy;
16008   int current_depth = 0;
16009
16010   g_queue_push_tail (queue, actor);
16011   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
16012
16013   while ((actor = g_queue_pop_head (queue)))
16014     {
16015       ClutterActorTraverseVisitFlags flags;
16016
16017       if (actor == &dummy)
16018         {
16019           current_depth++;
16020           g_queue_push_tail (queue, &dummy);
16021           continue;
16022         }
16023
16024       flags = callback (actor, current_depth, user_data);
16025       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16026         break;
16027       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16028         {
16029           ClutterActor *iter;
16030
16031           for (iter = actor->priv->first_child;
16032                iter != NULL;
16033                iter = iter->priv->next_sibling)
16034             {
16035               g_queue_push_tail (queue, iter);
16036             }
16037         }
16038     }
16039
16040   g_queue_free (queue);
16041 }
16042
16043 static ClutterActorTraverseVisitFlags
16044 _clutter_actor_traverse_depth (ClutterActor           *actor,
16045                                ClutterTraverseCallback before_children_callback,
16046                                ClutterTraverseCallback after_children_callback,
16047                                int                     current_depth,
16048                                gpointer                user_data)
16049 {
16050   ClutterActorTraverseVisitFlags flags;
16051
16052   flags = before_children_callback (actor, current_depth, user_data);
16053   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16054     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16055
16056   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16057     {
16058       ClutterActor *iter;
16059
16060       for (iter = actor->priv->first_child;
16061            iter != NULL;
16062            iter = iter->priv->next_sibling)
16063         {
16064           flags = _clutter_actor_traverse_depth (iter,
16065                                                  before_children_callback,
16066                                                  after_children_callback,
16067                                                  current_depth + 1,
16068                                                  user_data);
16069
16070           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16071             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16072         }
16073     }
16074
16075   if (after_children_callback)
16076     return after_children_callback (actor, current_depth, user_data);
16077   else
16078     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16079 }
16080
16081 /* _clutter_actor_traverse:
16082  * @actor: The actor to start traversing the graph from
16083  * @flags: These flags may affect how the traversal is done
16084  * @before_children_callback: A function to call before visiting the
16085  *   children of the current actor.
16086  * @after_children_callback: A function to call after visiting the
16087  *   children of the current actor. (Ignored if
16088  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
16089  * @user_data: The private data to pass to the callbacks
16090  *
16091  * Traverses the scenegraph starting at the specified @actor and
16092  * descending through all its children and its children's children.
16093  * For each actor traversed @before_children_callback and
16094  * @after_children_callback are called with the specified
16095  * @user_data, before and after visiting that actor's children.
16096  *
16097  * The callbacks can return flags that affect the ongoing traversal
16098  * such as by skipping over an actors children or bailing out of
16099  * any further traversing.
16100  */
16101 void
16102 _clutter_actor_traverse (ClutterActor              *actor,
16103                          ClutterActorTraverseFlags  flags,
16104                          ClutterTraverseCallback    before_children_callback,
16105                          ClutterTraverseCallback    after_children_callback,
16106                          gpointer                   user_data)
16107 {
16108   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
16109     _clutter_actor_traverse_breadth (actor,
16110                                      before_children_callback,
16111                                      user_data);
16112   else /* DEPTH_FIRST */
16113     _clutter_actor_traverse_depth (actor,
16114                                    before_children_callback,
16115                                    after_children_callback,
16116                                    0, /* start depth */
16117                                    user_data);
16118 }
16119
16120 static void
16121 on_layout_manager_changed (ClutterLayoutManager *manager,
16122                            ClutterActor         *self)
16123 {
16124   clutter_actor_queue_relayout (self);
16125 }
16126
16127 /**
16128  * clutter_actor_set_layout_manager:
16129  * @self: a #ClutterActor
16130  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
16131  *
16132  * Sets the #ClutterLayoutManager delegate object that will be used to
16133  * lay out the children of @self.
16134  *
16135  * The #ClutterActor will take a reference on the passed @manager which
16136  * will be released either when the layout manager is removed, or when
16137  * the actor is destroyed.
16138  *
16139  * Since: 1.10
16140  */
16141 void
16142 clutter_actor_set_layout_manager (ClutterActor         *self,
16143                                   ClutterLayoutManager *manager)
16144 {
16145   ClutterActorPrivate *priv;
16146
16147   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16148   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16149
16150   priv = self->priv;
16151
16152   if (priv->layout_manager != NULL)
16153     {
16154       g_signal_handlers_disconnect_by_func (priv->layout_manager,
16155                                             G_CALLBACK (on_layout_manager_changed),
16156                                             self);
16157       clutter_layout_manager_set_container (priv->layout_manager, NULL);
16158       g_clear_object (&priv->layout_manager);
16159     }
16160
16161   priv->layout_manager = manager;
16162
16163   if (priv->layout_manager != NULL)
16164     {
16165       g_object_ref_sink (priv->layout_manager);
16166       clutter_layout_manager_set_container (priv->layout_manager,
16167                                             CLUTTER_CONTAINER (self));
16168       g_signal_connect (priv->layout_manager, "layout-changed",
16169                         G_CALLBACK (on_layout_manager_changed),
16170                         self);
16171     }
16172
16173   clutter_actor_queue_relayout (self);
16174
16175   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16176 }
16177
16178 /**
16179  * clutter_actor_get_layout_manager:
16180  * @self: a #ClutterActor
16181  *
16182  * Retrieves the #ClutterLayoutManager used by @self.
16183  *
16184  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16185  *   or %NULL
16186  *
16187  * Since: 1.10
16188  */
16189 ClutterLayoutManager *
16190 clutter_actor_get_layout_manager (ClutterActor *self)
16191 {
16192   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16193
16194   return self->priv->layout_manager;
16195 }
16196
16197 static const ClutterLayoutInfo default_layout_info = {
16198   CLUTTER_POINT_INIT_ZERO,      /* fixed-pos */
16199   { 0, 0, 0, 0 },               /* margin */
16200   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
16201   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
16202   FALSE, FALSE,                 /* expand */
16203   CLUTTER_SIZE_INIT_ZERO,       /* minimum */
16204   CLUTTER_SIZE_INIT_ZERO,       /* natural */
16205 };
16206
16207 static void
16208 layout_info_free (gpointer data)
16209 {
16210   if (G_LIKELY (data != NULL))
16211     g_slice_free (ClutterLayoutInfo, data);
16212 }
16213
16214 /*< private >
16215  * _clutter_actor_get_layout_info:
16216  * @self: a #ClutterActor
16217  *
16218  * Retrieves a pointer to the ClutterLayoutInfo structure.
16219  *
16220  * If the actor does not have a ClutterLayoutInfo associated to it, one
16221  * will be created and initialized to the default values.
16222  *
16223  * This function should be used for setters.
16224  *
16225  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16226  * instead.
16227  *
16228  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16229  */
16230 ClutterLayoutInfo *
16231 _clutter_actor_get_layout_info (ClutterActor *self)
16232 {
16233   ClutterLayoutInfo *retval;
16234
16235   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16236   if (retval == NULL)
16237     {
16238       retval = g_slice_new (ClutterLayoutInfo);
16239
16240       *retval = default_layout_info;
16241
16242       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16243                                retval,
16244                                layout_info_free);
16245     }
16246
16247   return retval;
16248 }
16249
16250 /*< private >
16251  * _clutter_actor_get_layout_info_or_defaults:
16252  * @self: a #ClutterActor
16253  *
16254  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16255  *
16256  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16257  * then the default structure will be returned.
16258  *
16259  * This function should only be used for getters.
16260  *
16261  * Return value: a const pointer to the ClutterLayoutInfo structure
16262  */
16263 const ClutterLayoutInfo *
16264 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16265 {
16266   const ClutterLayoutInfo *info;
16267
16268   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16269   if (info == NULL)
16270     return &default_layout_info;
16271
16272   return info;
16273 }
16274
16275 /**
16276  * clutter_actor_set_x_align:
16277  * @self: a #ClutterActor
16278  * @x_align: the horizontal alignment policy
16279  *
16280  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16281  * actor received extra horizontal space.
16282  *
16283  * See also the #ClutterActor:x-align property.
16284  *
16285  * Since: 1.10
16286  */
16287 void
16288 clutter_actor_set_x_align (ClutterActor      *self,
16289                            ClutterActorAlign  x_align)
16290 {
16291   ClutterLayoutInfo *info;
16292
16293   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16294
16295   info = _clutter_actor_get_layout_info (self);
16296
16297   if (info->x_align != x_align)
16298     {
16299       info->x_align = x_align;
16300
16301       clutter_actor_queue_relayout (self);
16302
16303       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16304     }
16305 }
16306
16307 /**
16308  * clutter_actor_get_x_align:
16309  * @self: a #ClutterActor
16310  *
16311  * Retrieves the horizontal alignment policy set using
16312  * clutter_actor_set_x_align().
16313  *
16314  * Return value: the horizontal alignment policy.
16315  *
16316  * Since: 1.10
16317  */
16318 ClutterActorAlign
16319 clutter_actor_get_x_align (ClutterActor *self)
16320 {
16321   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16322
16323   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16324 }
16325
16326 /**
16327  * clutter_actor_set_y_align:
16328  * @self: a #ClutterActor
16329  * @y_align: the vertical alignment policy
16330  *
16331  * Sets the vertical alignment policy of a #ClutterActor, in case the
16332  * actor received extra vertical space.
16333  *
16334  * See also the #ClutterActor:y-align property.
16335  *
16336  * Since: 1.10
16337  */
16338 void
16339 clutter_actor_set_y_align (ClutterActor      *self,
16340                            ClutterActorAlign  y_align)
16341 {
16342   ClutterLayoutInfo *info;
16343
16344   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16345
16346   info = _clutter_actor_get_layout_info (self);
16347
16348   if (info->y_align != y_align)
16349     {
16350       info->y_align = y_align;
16351
16352       clutter_actor_queue_relayout (self);
16353
16354       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16355     }
16356 }
16357
16358 /**
16359  * clutter_actor_get_y_align:
16360  * @self: a #ClutterActor
16361  *
16362  * Retrieves the vertical alignment policy set using
16363  * clutter_actor_set_y_align().
16364  *
16365  * Return value: the vertical alignment policy.
16366  *
16367  * Since: 1.10
16368  */
16369 ClutterActorAlign
16370 clutter_actor_get_y_align (ClutterActor *self)
16371 {
16372   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16373
16374   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16375 }
16376
16377 /**
16378  * clutter_actor_set_margin:
16379  * @self: a #ClutterActor
16380  * @margin: a #ClutterMargin
16381  *
16382  * Sets all the components of the margin of a #ClutterActor.
16383  *
16384  * Since: 1.10
16385  */
16386 void
16387 clutter_actor_set_margin (ClutterActor        *self,
16388                           const ClutterMargin *margin)
16389 {
16390   ClutterLayoutInfo *info;
16391   gboolean changed;
16392   GObject *obj;
16393
16394   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16395   g_return_if_fail (margin != NULL);
16396
16397   obj = G_OBJECT (self);
16398   changed = FALSE;
16399
16400   g_object_freeze_notify (obj);
16401
16402   info = _clutter_actor_get_layout_info (self);
16403
16404   if (info->margin.top != margin->top)
16405     {
16406       info->margin.top = margin->top;
16407       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16408       changed = TRUE;
16409     }
16410
16411   if (info->margin.right != margin->right)
16412     {
16413       info->margin.right = margin->right;
16414       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16415       changed = TRUE;
16416     }
16417
16418   if (info->margin.bottom != margin->bottom)
16419     {
16420       info->margin.bottom = margin->bottom;
16421       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16422       changed = TRUE;
16423     }
16424
16425   if (info->margin.left != margin->left)
16426     {
16427       info->margin.left = margin->left;
16428       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16429       changed = TRUE;
16430     }
16431
16432   if (changed)
16433     clutter_actor_queue_relayout (self);
16434
16435   g_object_thaw_notify (obj);
16436 }
16437
16438 /**
16439  * clutter_actor_get_margin:
16440  * @self: a #ClutterActor
16441  * @margin: (out caller-allocates): return location for a #ClutterMargin
16442  *
16443  * Retrieves all the components of the margin of a #ClutterActor.
16444  *
16445  * Since: 1.10
16446  */
16447 void
16448 clutter_actor_get_margin (ClutterActor  *self,
16449                           ClutterMargin *margin)
16450 {
16451   const ClutterLayoutInfo *info;
16452
16453   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16454   g_return_if_fail (margin != NULL);
16455
16456   info = _clutter_actor_get_layout_info_or_defaults (self);
16457
16458   *margin = info->margin;
16459 }
16460
16461 /**
16462  * clutter_actor_set_margin_top:
16463  * @self: a #ClutterActor
16464  * @margin: the top margin
16465  *
16466  * Sets the margin from the top of a #ClutterActor.
16467  *
16468  * Since: 1.10
16469  */
16470 void
16471 clutter_actor_set_margin_top (ClutterActor *self,
16472                               gfloat        margin)
16473 {
16474   ClutterLayoutInfo *info;
16475
16476   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16477   g_return_if_fail (margin >= 0.f);
16478
16479   info = _clutter_actor_get_layout_info (self);
16480
16481   if (info->margin.top == margin)
16482     return;
16483
16484   info->margin.top = margin;
16485
16486   clutter_actor_queue_relayout (self);
16487
16488   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16489 }
16490
16491 /**
16492  * clutter_actor_get_margin_top:
16493  * @self: a #ClutterActor
16494  *
16495  * Retrieves the top margin of a #ClutterActor.
16496  *
16497  * Return value: the top margin
16498  *
16499  * Since: 1.10
16500  */
16501 gfloat
16502 clutter_actor_get_margin_top (ClutterActor *self)
16503 {
16504   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16505
16506   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16507 }
16508
16509 /**
16510  * clutter_actor_set_margin_bottom:
16511  * @self: a #ClutterActor
16512  * @margin: the bottom margin
16513  *
16514  * Sets the margin from the bottom of a #ClutterActor.
16515  *
16516  * Since: 1.10
16517  */
16518 void
16519 clutter_actor_set_margin_bottom (ClutterActor *self,
16520                                  gfloat        margin)
16521 {
16522   ClutterLayoutInfo *info;
16523
16524   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16525   g_return_if_fail (margin >= 0.f);
16526
16527   info = _clutter_actor_get_layout_info (self);
16528
16529   if (info->margin.bottom == margin)
16530     return;
16531
16532   info->margin.bottom = margin;
16533
16534   clutter_actor_queue_relayout (self);
16535
16536   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16537 }
16538
16539 /**
16540  * clutter_actor_get_margin_bottom:
16541  * @self: a #ClutterActor
16542  *
16543  * Retrieves the bottom margin of a #ClutterActor.
16544  *
16545  * Return value: the bottom margin
16546  *
16547  * Since: 1.10
16548  */
16549 gfloat
16550 clutter_actor_get_margin_bottom (ClutterActor *self)
16551 {
16552   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16553
16554   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16555 }
16556
16557 /**
16558  * clutter_actor_set_margin_left:
16559  * @self: a #ClutterActor
16560  * @margin: the left margin
16561  *
16562  * Sets the margin from the left of a #ClutterActor.
16563  *
16564  * Since: 1.10
16565  */
16566 void
16567 clutter_actor_set_margin_left (ClutterActor *self,
16568                                gfloat        margin)
16569 {
16570   ClutterLayoutInfo *info;
16571
16572   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16573   g_return_if_fail (margin >= 0.f);
16574
16575   info = _clutter_actor_get_layout_info (self);
16576
16577   if (info->margin.left == margin)
16578     return;
16579
16580   info->margin.left = margin;
16581
16582   clutter_actor_queue_relayout (self);
16583
16584   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16585 }
16586
16587 /**
16588  * clutter_actor_get_margin_left:
16589  * @self: a #ClutterActor
16590  *
16591  * Retrieves the left margin of a #ClutterActor.
16592  *
16593  * Return value: the left margin
16594  *
16595  * Since: 1.10
16596  */
16597 gfloat
16598 clutter_actor_get_margin_left (ClutterActor *self)
16599 {
16600   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16601
16602   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16603 }
16604
16605 /**
16606  * clutter_actor_set_margin_right:
16607  * @self: a #ClutterActor
16608  * @margin: the right margin
16609  *
16610  * Sets the margin from the right of a #ClutterActor.
16611  *
16612  * Since: 1.10
16613  */
16614 void
16615 clutter_actor_set_margin_right (ClutterActor *self,
16616                                 gfloat        margin)
16617 {
16618   ClutterLayoutInfo *info;
16619
16620   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16621   g_return_if_fail (margin >= 0.f);
16622
16623   info = _clutter_actor_get_layout_info (self);
16624
16625   if (info->margin.right == margin)
16626     return;
16627
16628   info->margin.right = margin;
16629
16630   clutter_actor_queue_relayout (self);
16631
16632   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16633 }
16634
16635 /**
16636  * clutter_actor_get_margin_right:
16637  * @self: a #ClutterActor
16638  *
16639  * Retrieves the right margin of a #ClutterActor.
16640  *
16641  * Return value: the right margin
16642  *
16643  * Since: 1.10
16644  */
16645 gfloat
16646 clutter_actor_get_margin_right (ClutterActor *self)
16647 {
16648   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16649
16650   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16651 }
16652
16653 static inline void
16654 clutter_actor_set_background_color_internal (ClutterActor *self,
16655                                              const ClutterColor *color)
16656 {
16657   ClutterActorPrivate *priv = self->priv;
16658   GObject *obj;
16659
16660   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16661     return;
16662
16663   obj = G_OBJECT (self);
16664
16665   priv->bg_color = *color;
16666   priv->bg_color_set = TRUE;
16667
16668   clutter_actor_queue_redraw (self);
16669
16670   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16671   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16672 }
16673
16674 /**
16675  * clutter_actor_set_background_color:
16676  * @self: a #ClutterActor
16677  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16678  *  set color
16679  *
16680  * Sets the background color of a #ClutterActor.
16681  *
16682  * The background color will be used to cover the whole allocation of the
16683  * actor. The default background color of an actor is transparent.
16684  *
16685  * To check whether an actor has a background color, you can use the
16686  * #ClutterActor:background-color-set actor property.
16687  *
16688  * The #ClutterActor:background-color property is animatable.
16689  *
16690  * Since: 1.10
16691  */
16692 void
16693 clutter_actor_set_background_color (ClutterActor       *self,
16694                                     const ClutterColor *color)
16695 {
16696   ClutterActorPrivate *priv;
16697   GObject *obj;
16698   GParamSpec *bg_color_pspec;
16699
16700   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16701
16702   obj = G_OBJECT (self);
16703
16704   priv = self->priv;
16705
16706   if (color == NULL)
16707     {
16708       priv->bg_color_set = FALSE;
16709       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16710       clutter_actor_queue_redraw (self);
16711       return;
16712     }
16713
16714   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16715   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16716     {
16717       _clutter_actor_create_transition (self, bg_color_pspec,
16718                                         &priv->bg_color,
16719                                         color);
16720     }
16721   else
16722     _clutter_actor_update_transition (self, bg_color_pspec, color);
16723
16724   clutter_actor_queue_redraw (self);
16725 }
16726
16727 /**
16728  * clutter_actor_get_background_color:
16729  * @self: a #ClutterActor
16730  * @color: (out caller-allocates): return location for a #ClutterColor
16731  *
16732  * Retrieves the color set using clutter_actor_set_background_color().
16733  *
16734  * Since: 1.10
16735  */
16736 void
16737 clutter_actor_get_background_color (ClutterActor *self,
16738                                     ClutterColor *color)
16739 {
16740   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16741   g_return_if_fail (color != NULL);
16742
16743   *color = self->priv->bg_color;
16744 }
16745
16746 /**
16747  * clutter_actor_get_previous_sibling:
16748  * @self: a #ClutterActor
16749  *
16750  * Retrieves the sibling of @self that comes before it in the list
16751  * of children of @self's parent.
16752  *
16753  * The returned pointer is only valid until the scene graph changes; it
16754  * is not safe to modify the list of children of @self while iterating
16755  * it.
16756  *
16757  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16758  *
16759  * Since: 1.10
16760  */
16761 ClutterActor *
16762 clutter_actor_get_previous_sibling (ClutterActor *self)
16763 {
16764   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16765
16766   return self->priv->prev_sibling;
16767 }
16768
16769 /**
16770  * clutter_actor_get_next_sibling:
16771  * @self: a #ClutterActor
16772  *
16773  * Retrieves the sibling of @self that comes after it in the list
16774  * of children of @self's parent.
16775  *
16776  * The returned pointer is only valid until the scene graph changes; it
16777  * is not safe to modify the list of children of @self while iterating
16778  * it.
16779  *
16780  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16781  *
16782  * Since: 1.10
16783  */
16784 ClutterActor *
16785 clutter_actor_get_next_sibling (ClutterActor *self)
16786 {
16787   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16788
16789   return self->priv->next_sibling;
16790 }
16791
16792 /**
16793  * clutter_actor_get_first_child:
16794  * @self: a #ClutterActor
16795  *
16796  * Retrieves the first child of @self.
16797  *
16798  * The returned pointer is only valid until the scene graph changes; it
16799  * is not safe to modify the list of children of @self while iterating
16800  * it.
16801  *
16802  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16803  *
16804  * Since: 1.10
16805  */
16806 ClutterActor *
16807 clutter_actor_get_first_child (ClutterActor *self)
16808 {
16809   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16810
16811   return self->priv->first_child;
16812 }
16813
16814 /**
16815  * clutter_actor_get_last_child:
16816  * @self: a #ClutterActor
16817  *
16818  * Retrieves the last child of @self.
16819  *
16820  * The returned pointer is only valid until the scene graph changes; it
16821  * is not safe to modify the list of children of @self while iterating
16822  * it.
16823  *
16824  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16825  *
16826  * Since: 1.10
16827  */
16828 ClutterActor *
16829 clutter_actor_get_last_child (ClutterActor *self)
16830 {
16831   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16832
16833   return self->priv->last_child;
16834 }
16835
16836 /* easy way to have properly named fields instead of the dummy ones
16837  * we use in the public structure
16838  */
16839 typedef struct _RealActorIter
16840 {
16841   ClutterActor *root;           /* dummy1 */
16842   ClutterActor *current;        /* dummy2 */
16843   gpointer padding_1;           /* dummy3 */
16844   gint age;                     /* dummy4 */
16845   gpointer padding_2;           /* dummy5 */
16846 } RealActorIter;
16847
16848 /**
16849  * clutter_actor_iter_init:
16850  * @iter: a #ClutterActorIter
16851  * @root: a #ClutterActor
16852  *
16853  * Initializes a #ClutterActorIter, which can then be used to iterate
16854  * efficiently over a section of the scene graph, and associates it
16855  * with @root.
16856  *
16857  * Modifying the scene graph section that contains @root will invalidate
16858  * the iterator.
16859  *
16860  * |[
16861  *   ClutterActorIter iter;
16862  *   ClutterActor *child;
16863  *
16864  *   clutter_actor_iter_init (&iter, container);
16865  *   while (clutter_actor_iter_next (&iter, &child))
16866  *     {
16867  *       /&ast; do something with child &ast;/
16868  *     }
16869  * ]|
16870  *
16871  * Since: 1.10
16872  */
16873 void
16874 clutter_actor_iter_init (ClutterActorIter *iter,
16875                          ClutterActor     *root)
16876 {
16877   RealActorIter *ri = (RealActorIter *) iter;
16878
16879   g_return_if_fail (iter != NULL);
16880   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16881
16882   ri->root = root;
16883   ri->current = NULL;
16884   ri->age = root->priv->age;
16885 }
16886
16887 /**
16888  * clutter_actor_iter_next:
16889  * @iter: a #ClutterActorIter
16890  * @child: (out): return location for a #ClutterActor
16891  *
16892  * Advances the @iter and retrieves the next child of the root #ClutterActor
16893  * that was used to initialize the #ClutterActorIterator.
16894  *
16895  * If the iterator can advance, this function returns %TRUE and sets the
16896  * @child argument.
16897  *
16898  * If the iterator cannot advance, this function returns %FALSE, and
16899  * the contents of @child are undefined.
16900  *
16901  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16902  *
16903  * Since: 1.10
16904  */
16905 gboolean
16906 clutter_actor_iter_next (ClutterActorIter  *iter,
16907                          ClutterActor     **child)
16908 {
16909   RealActorIter *ri = (RealActorIter *) iter;
16910
16911   g_return_val_if_fail (iter != NULL, FALSE);
16912   g_return_val_if_fail (ri->root != NULL, FALSE);
16913 #ifndef G_DISABLE_ASSERT
16914   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16915 #endif
16916
16917   if (ri->current == NULL)
16918     ri->current = ri->root->priv->first_child;
16919   else
16920     ri->current = ri->current->priv->next_sibling;
16921
16922   if (child != NULL)
16923     *child = ri->current;
16924
16925   return ri->current != NULL;
16926 }
16927
16928 /**
16929  * clutter_actor_iter_prev:
16930  * @iter: a #ClutterActorIter
16931  * @child: (out): return location for a #ClutterActor
16932  *
16933  * Advances the @iter and retrieves the previous child of the root
16934  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16935  *
16936  * If the iterator can advance, this function returns %TRUE and sets the
16937  * @child argument.
16938  *
16939  * If the iterator cannot advance, this function returns %FALSE, and
16940  * the contents of @child are undefined.
16941  *
16942  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16943  *
16944  * Since: 1.10
16945  */
16946 gboolean
16947 clutter_actor_iter_prev (ClutterActorIter  *iter,
16948                          ClutterActor     **child)
16949 {
16950   RealActorIter *ri = (RealActorIter *) iter;
16951
16952   g_return_val_if_fail (iter != NULL, FALSE);
16953   g_return_val_if_fail (ri->root != NULL, FALSE);
16954 #ifndef G_DISABLE_ASSERT
16955   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16956 #endif
16957
16958   if (ri->current == NULL)
16959     ri->current = ri->root->priv->last_child;
16960   else
16961     ri->current = ri->current->priv->prev_sibling;
16962
16963   if (child != NULL)
16964     *child = ri->current;
16965
16966   return ri->current != NULL;
16967 }
16968
16969 /**
16970  * clutter_actor_iter_remove:
16971  * @iter: a #ClutterActorIter
16972  *
16973  * Safely removes the #ClutterActor currently pointer to by the iterator
16974  * from its parent.
16975  *
16976  * This function can only be called after clutter_actor_iter_next() or
16977  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16978  * than once for the same actor.
16979  *
16980  * This function will call clutter_actor_remove_child() internally.
16981  *
16982  * Since: 1.10
16983  */
16984 void
16985 clutter_actor_iter_remove (ClutterActorIter *iter)
16986 {
16987   RealActorIter *ri = (RealActorIter *) iter;
16988   ClutterActor *cur;
16989
16990   g_return_if_fail (iter != NULL);
16991   g_return_if_fail (ri->root != NULL);
16992 #ifndef G_DISABLE_ASSERT
16993   g_return_if_fail (ri->age == ri->root->priv->age);
16994 #endif
16995   g_return_if_fail (ri->current != NULL);
16996
16997   cur = ri->current;
16998
16999   if (cur != NULL)
17000     {
17001       ri->current = cur->priv->prev_sibling;
17002
17003       clutter_actor_remove_child_internal (ri->root, cur,
17004                                            REMOVE_CHILD_DEFAULT_FLAGS);
17005
17006       ri->age += 1;
17007     }
17008 }
17009
17010 /**
17011  * clutter_actor_iter_destroy:
17012  * @iter: a #ClutterActorIter
17013  *
17014  * Safely destroys the #ClutterActor currently pointer to by the iterator
17015  * from its parent.
17016  *
17017  * This function can only be called after clutter_actor_iter_next() or
17018  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17019  * than once for the same actor.
17020  *
17021  * This function will call clutter_actor_destroy() internally.
17022  *
17023  * Since: 1.10
17024  */
17025 void
17026 clutter_actor_iter_destroy (ClutterActorIter *iter)
17027 {
17028   RealActorIter *ri = (RealActorIter *) iter;
17029   ClutterActor *cur;
17030
17031   g_return_if_fail (iter != NULL);
17032   g_return_if_fail (ri->root != NULL);
17033 #ifndef G_DISABLE_ASSERT
17034   g_return_if_fail (ri->age == ri->root->priv->age);
17035 #endif
17036   g_return_if_fail (ri->current != NULL);
17037
17038   cur = ri->current;
17039
17040   if (cur != NULL)
17041     {
17042       ri->current = cur->priv->prev_sibling;
17043
17044       clutter_actor_destroy (cur);
17045
17046       ri->age += 1;
17047     }
17048 }
17049
17050 static const ClutterAnimationInfo default_animation_info = {
17051   NULL,         /* transitions */
17052   NULL,         /* states */
17053   NULL,         /* cur_state */
17054 };
17055
17056 static void
17057 clutter_animation_info_free (gpointer data)
17058 {
17059   if (data != NULL)
17060     {
17061       ClutterAnimationInfo *info = data;
17062
17063       if (info->transitions != NULL)
17064         g_hash_table_unref (info->transitions);
17065
17066       if (info->states != NULL)
17067         g_array_unref (info->states);
17068
17069       g_slice_free (ClutterAnimationInfo, info);
17070     }
17071 }
17072
17073 const ClutterAnimationInfo *
17074 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17075 {
17076   const ClutterAnimationInfo *res;
17077   GObject *obj = G_OBJECT (self);
17078
17079   res = g_object_get_qdata (obj, quark_actor_animation_info);
17080   if (res != NULL)
17081     return res;
17082
17083   return &default_animation_info;
17084 }
17085
17086 ClutterAnimationInfo *
17087 _clutter_actor_get_animation_info (ClutterActor *self)
17088 {
17089   GObject *obj = G_OBJECT (self);
17090   ClutterAnimationInfo *res;
17091
17092   res = g_object_get_qdata (obj, quark_actor_animation_info);
17093   if (res == NULL)
17094     {
17095       res = g_slice_new (ClutterAnimationInfo);
17096
17097       *res = default_animation_info;
17098
17099       g_object_set_qdata_full (obj, quark_actor_animation_info,
17100                                res,
17101                                clutter_animation_info_free);
17102     }
17103
17104   return res;
17105 }
17106
17107 ClutterTransition *
17108 _clutter_actor_get_transition (ClutterActor *actor,
17109                                GParamSpec   *pspec)
17110 {
17111   const ClutterAnimationInfo *info;
17112
17113   info = _clutter_actor_get_animation_info_or_defaults (actor);
17114
17115   if (info->transitions == NULL)
17116     return NULL;
17117
17118   return g_hash_table_lookup (info->transitions, pspec->name);
17119 }
17120
17121 typedef struct _TransitionClosure
17122 {
17123   ClutterActor *actor;
17124   ClutterTransition *transition;
17125   gchar *name;
17126   gulong completed_id;
17127 } TransitionClosure;
17128
17129 static void
17130 transition_closure_free (gpointer data)
17131 {
17132   if (G_LIKELY (data != NULL))
17133     {
17134       TransitionClosure *clos = data;
17135       ClutterTimeline *timeline;
17136
17137       timeline = CLUTTER_TIMELINE (clos->transition);
17138
17139       if (clutter_timeline_is_playing (timeline))
17140         clutter_timeline_stop (timeline);
17141
17142       g_signal_handler_disconnect (clos->transition, clos->completed_id);
17143
17144       g_object_unref (clos->transition);
17145       g_free (clos->name);
17146
17147       g_slice_free (TransitionClosure, clos);
17148     }
17149 }
17150
17151 static void
17152 on_transition_completed (ClutterTransition *transition,
17153                          TransitionClosure *clos)
17154 {
17155   ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
17156   ClutterActor *actor = clos->actor;
17157   ClutterAnimationInfo *info;
17158   gint n_repeats, cur_repeat;
17159
17160   info = _clutter_actor_get_animation_info (actor);
17161
17162   /* reset the caches used by animations */
17163   clutter_actor_store_content_box (actor, NULL);
17164
17165   /* ensure that we remove the transition only at the end
17166    * of its run; we emit ::completed for every repeat
17167    */
17168   n_repeats = clutter_timeline_get_repeat_count (timeline);
17169   cur_repeat = clutter_timeline_get_current_repeat (timeline);
17170
17171   if (cur_repeat == n_repeats)
17172     {
17173       if (clutter_transition_get_remove_on_complete (transition))
17174         {
17175           /* we take a reference here because removing the closure
17176            * will release the reference on the transition, and we
17177            * want the transition to survive the signal emission;
17178            * the master clock will release the last reference at
17179            * the end of the frame processing.
17180            */
17181           g_object_ref (transition);
17182           g_hash_table_remove (info->transitions, clos->name);
17183         }
17184     }
17185
17186   /* if it's the last transition then we clean up */
17187   if (g_hash_table_size (info->transitions) == 0)
17188     {
17189       g_hash_table_unref (info->transitions);
17190       info->transitions = NULL;
17191
17192       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17193                     _clutter_actor_get_debug_name (actor));
17194
17195       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17196     }
17197 }
17198
17199 void
17200 _clutter_actor_update_transition (ClutterActor *actor,
17201                                   GParamSpec   *pspec,
17202                                   ...)
17203 {
17204   TransitionClosure *clos;
17205   ClutterTimeline *timeline;
17206   ClutterInterval *interval;
17207   const ClutterAnimationInfo *info;
17208   va_list var_args;
17209   GType ptype;
17210   GValue initial = G_VALUE_INIT;
17211   GValue final = G_VALUE_INIT;
17212   char *error = NULL;
17213
17214   info = _clutter_actor_get_animation_info_or_defaults (actor);
17215
17216   if (info->transitions == NULL)
17217     return;
17218
17219   clos = g_hash_table_lookup (info->transitions, pspec->name);
17220   if (clos == NULL)
17221     return;
17222
17223   timeline = CLUTTER_TIMELINE (clos->transition);
17224
17225   va_start (var_args, pspec);
17226
17227   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17228
17229   g_value_init (&initial, ptype);
17230   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17231                                         pspec->name,
17232                                         &initial);
17233
17234   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17235   if (error != NULL)
17236     {
17237       g_critical ("%s: %s", G_STRLOC, error);
17238       g_free (error);
17239       goto out;
17240     }
17241
17242   interval = clutter_transition_get_interval (clos->transition);
17243   clutter_interval_set_initial_value (interval, &initial);
17244   clutter_interval_set_final_value (interval, &final);
17245
17246   /* if we're updating with an easing duration of zero milliseconds,
17247    * we just jump the timeline to the end and let it run its course
17248    */
17249   if (info->cur_state != NULL &&
17250       info->cur_state->easing_duration != 0)
17251     {
17252       guint cur_duration = clutter_timeline_get_duration (timeline);
17253       ClutterAnimationMode cur_mode =
17254         clutter_timeline_get_progress_mode (timeline);
17255
17256       if (cur_duration != info->cur_state->easing_duration)
17257         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17258
17259       if (cur_mode != info->cur_state->easing_mode)
17260         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17261
17262       clutter_timeline_rewind (timeline);
17263     }
17264   else
17265     {
17266       guint duration = clutter_timeline_get_duration (timeline);
17267
17268       clutter_timeline_advance (timeline, duration);
17269     }
17270
17271 out:
17272   g_value_unset (&initial);
17273   g_value_unset (&final);
17274
17275   va_end (var_args);
17276 }
17277
17278 /*< private >*
17279  * _clutter_actor_create_transition:
17280  * @actor: a #ClutterActor
17281  * @pspec: the property used for the transition
17282  * @...: initial and final state
17283  *
17284  * Creates a #ClutterTransition for the property represented by @pspec.
17285  *
17286  * Return value: a #ClutterTransition
17287  */
17288 ClutterTransition *
17289 _clutter_actor_create_transition (ClutterActor *actor,
17290                                   GParamSpec   *pspec,
17291                                   ...)
17292 {
17293   ClutterAnimationInfo *info;
17294   ClutterTransition *res = NULL;
17295   gboolean call_restore = FALSE;
17296   TransitionClosure *clos;
17297   va_list var_args;
17298
17299   info = _clutter_actor_get_animation_info (actor);
17300
17301   /* XXX - this will go away in 2.0
17302    *
17303    * if no state has been pushed, we assume that the easing state is
17304    * in "compatibility mode": all transitions have a duration of 0
17305    * msecs, which means that they happen immediately. in Clutter 2.0
17306    * this will turn into a g_assert(info->states != NULL), as every
17307    * actor will start with a predefined easing state
17308    */
17309   if (info->states == NULL)
17310     {
17311       clutter_actor_save_easing_state (actor);
17312       clutter_actor_set_easing_duration (actor, 0);
17313       call_restore = TRUE;
17314     }
17315
17316   if (info->transitions == NULL)
17317     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17318                                                NULL,
17319                                                transition_closure_free);
17320
17321   va_start (var_args, pspec);
17322
17323   clos = g_hash_table_lookup (info->transitions, pspec->name);
17324   if (clos == NULL)
17325     {
17326       ClutterTimeline *timeline;
17327       ClutterInterval *interval;
17328       GValue initial = G_VALUE_INIT;
17329       GValue final = G_VALUE_INIT;
17330       GType ptype;
17331       char *error;
17332
17333       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17334
17335       G_VALUE_COLLECT_INIT (&initial, ptype,
17336                             var_args, 0,
17337                             &error);
17338       if (error != NULL)
17339         {
17340           g_critical ("%s: %s", G_STRLOC, error);
17341           g_free (error);
17342           goto out;
17343         }
17344
17345       G_VALUE_COLLECT_INIT (&final, ptype,
17346                             var_args, 0,
17347                             &error);
17348
17349       if (error != NULL)
17350         {
17351           g_critical ("%s: %s", G_STRLOC, error);
17352           g_value_unset (&initial);
17353           g_free (error);
17354           goto out;
17355         }
17356
17357       /* if the current easing state has a duration of 0, then we don't
17358        * bother to create the transition, and we just set the final value
17359        * directly on the actor; we don't go through the Animatable
17360        * interface because we know we got here through an animatable
17361        * property.
17362        */
17363       if (info->cur_state->easing_duration == 0)
17364         {
17365           clutter_actor_set_animatable_property (actor,
17366                                                  pspec->param_id,
17367                                                  &final,
17368                                                  pspec);
17369           g_value_unset (&initial);
17370           g_value_unset (&final);
17371
17372           goto out;
17373         }
17374
17375       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17376
17377       g_value_unset (&initial);
17378       g_value_unset (&final);
17379
17380       res = clutter_property_transition_new (pspec->name);
17381
17382       clutter_transition_set_interval (res, interval);
17383       clutter_transition_set_remove_on_complete (res, TRUE);
17384
17385       timeline = CLUTTER_TIMELINE (res);
17386       clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17387       clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17388       clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17389
17390       /* this will start the transition as well */
17391       clutter_actor_add_transition (actor, pspec->name, res);
17392
17393       /* the actor now owns the transition */
17394       g_object_unref (res);
17395     }
17396   else
17397     res = clos->transition;
17398
17399 out:
17400   if (call_restore)
17401     clutter_actor_restore_easing_state (actor);
17402
17403   va_end (var_args);
17404
17405   return res;
17406 }
17407
17408 /**
17409  * clutter_actor_add_transition:
17410  * @self: a #ClutterActor
17411  * @name: the name of the transition to add
17412  * @transition: the #ClutterTransition to add
17413  *
17414  * Adds a @transition to the #ClutterActor's list of animations.
17415  *
17416  * The @name string is a per-actor unique identifier of the @transition: only
17417  * one #ClutterTransition can be associated to the specified @name.
17418  *
17419  * The @transition will be started once added.
17420  *
17421  * This function will take a reference on the @transition.
17422  *
17423  * This function is usually called implicitly when modifying an animatable
17424  * property.
17425  *
17426  * Since: 1.10
17427  */
17428 void
17429 clutter_actor_add_transition (ClutterActor      *self,
17430                               const char        *name,
17431                               ClutterTransition *transition)
17432 {
17433   ClutterTimeline *timeline;
17434   TransitionClosure *clos;
17435   ClutterAnimationInfo *info;
17436
17437   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17438   g_return_if_fail (name != NULL);
17439   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17440
17441   info = _clutter_actor_get_animation_info (self);
17442
17443   if (info->transitions == NULL)
17444     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17445                                                NULL,
17446                                                transition_closure_free);
17447
17448   if (g_hash_table_lookup (info->transitions, name) != NULL)
17449     {
17450       g_warning ("A transition with name '%s' already exists for "
17451                  "the actor '%s'",
17452                  name,
17453                  _clutter_actor_get_debug_name (self));
17454       return;
17455     }
17456
17457   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17458
17459   timeline = CLUTTER_TIMELINE (transition);
17460
17461   clos = g_slice_new (TransitionClosure);
17462   clos->actor = self;
17463   clos->transition = g_object_ref (transition);
17464   clos->name = g_strdup (name);
17465   clos->completed_id = g_signal_connect (timeline, "completed",
17466                                          G_CALLBACK (on_transition_completed),
17467                                          clos);
17468
17469   CLUTTER_NOTE (ANIMATION,
17470                 "Adding transition '%s' [%p] to actor '%s'",
17471                 clos->name,
17472                 clos->transition,
17473                 _clutter_actor_get_debug_name (self));
17474
17475   g_hash_table_insert (info->transitions, clos->name, clos);
17476   clutter_timeline_start (timeline);
17477 }
17478
17479 /**
17480  * clutter_actor_remove_transition:
17481  * @self: a #ClutterActor
17482  * @name: the name of the transition to remove
17483  *
17484  * Removes the transition stored inside a #ClutterActor using @name
17485  * identifier.
17486  *
17487  * If the transition is currently in progress, it will be stopped.
17488  *
17489  * This function releases the reference acquired when the transition
17490  * was added to the #ClutterActor.
17491  *
17492  * Since: 1.10
17493  */
17494 void
17495 clutter_actor_remove_transition (ClutterActor *self,
17496                                  const char   *name)
17497 {
17498   const ClutterAnimationInfo *info;
17499
17500   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17501   g_return_if_fail (name != NULL);
17502
17503   info = _clutter_actor_get_animation_info_or_defaults (self);
17504
17505   if (info->transitions == NULL)
17506     return;
17507
17508   g_hash_table_remove (info->transitions, name);
17509 }
17510
17511 /**
17512  * clutter_actor_remove_all_transitions:
17513  * @self: a #ClutterActor
17514  *
17515  * Removes all transitions associated to @self.
17516  *
17517  * Since: 1.10
17518  */
17519 void
17520 clutter_actor_remove_all_transitions (ClutterActor *self)
17521 {
17522   const ClutterAnimationInfo *info;
17523
17524   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17525
17526   info = _clutter_actor_get_animation_info_or_defaults (self);
17527   if (info->transitions == NULL)
17528     return;
17529
17530   g_hash_table_remove_all (info->transitions);
17531 }
17532
17533 /**
17534  * clutter_actor_set_easing_duration:
17535  * @self: a #ClutterActor
17536  * @msecs: the duration of the easing, or %NULL
17537  *
17538  * Sets the duration of the tweening for animatable properties
17539  * of @self for the current easing state.
17540  *
17541  * Since: 1.10
17542  */
17543 void
17544 clutter_actor_set_easing_duration (ClutterActor *self,
17545                                    guint         msecs)
17546 {
17547   ClutterAnimationInfo *info;
17548
17549   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17550
17551   info = _clutter_actor_get_animation_info (self);
17552
17553   if (info->cur_state == NULL)
17554     {
17555       g_warning ("You must call clutter_actor_save_easing_state() prior "
17556                  "to calling clutter_actor_set_easing_duration().");
17557       return;
17558     }
17559
17560   if (info->cur_state->easing_duration != msecs)
17561     info->cur_state->easing_duration = msecs;
17562 }
17563
17564 /**
17565  * clutter_actor_get_easing_duration:
17566  * @self: a #ClutterActor
17567  *
17568  * Retrieves the duration of the tweening for animatable
17569  * properties of @self for the current easing state.
17570  *
17571  * Return value: the duration of the tweening, in milliseconds
17572  *
17573  * Since: 1.10
17574  */
17575 guint
17576 clutter_actor_get_easing_duration (ClutterActor *self)
17577 {
17578   const ClutterAnimationInfo *info;
17579
17580   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17581
17582   info = _clutter_actor_get_animation_info_or_defaults (self);
17583
17584   if (info->cur_state != NULL)
17585     return info->cur_state->easing_duration;
17586
17587   return 0;
17588 }
17589
17590 /**
17591  * clutter_actor_set_easing_mode:
17592  * @self: a #ClutterActor
17593  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17594  *
17595  * Sets the easing mode for the tweening of animatable properties
17596  * of @self.
17597  *
17598  * Since: 1.10
17599  */
17600 void
17601 clutter_actor_set_easing_mode (ClutterActor         *self,
17602                                ClutterAnimationMode  mode)
17603 {
17604   ClutterAnimationInfo *info;
17605
17606   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17607   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17608   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17609
17610   info = _clutter_actor_get_animation_info (self);
17611
17612   if (info->cur_state == NULL)
17613     {
17614       g_warning ("You must call clutter_actor_save_easing_state() prior "
17615                  "to calling clutter_actor_set_easing_mode().");
17616       return;
17617     }
17618
17619   if (info->cur_state->easing_mode != mode)
17620     info->cur_state->easing_mode = mode;
17621 }
17622
17623 /**
17624  * clutter_actor_get_easing_mode:
17625  * @self: a #ClutterActor
17626  *
17627  * Retrieves the easing mode for the tweening of animatable properties
17628  * of @self for the current easing state.
17629  *
17630  * Return value: an easing mode
17631  *
17632  * Since: 1.10
17633  */
17634 ClutterAnimationMode
17635 clutter_actor_get_easing_mode (ClutterActor *self)
17636 {
17637   const ClutterAnimationInfo *info;
17638
17639   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17640
17641   info = _clutter_actor_get_animation_info_or_defaults (self);
17642
17643   if (info->cur_state != NULL)
17644     return info->cur_state->easing_mode;
17645
17646   return CLUTTER_EASE_OUT_CUBIC;
17647 }
17648
17649 /**
17650  * clutter_actor_set_easing_delay:
17651  * @self: a #ClutterActor
17652  * @msecs: the delay before the start of the tweening, in milliseconds
17653  *
17654  * Sets the delay that should be applied before tweening animatable
17655  * properties.
17656  *
17657  * Since: 1.10
17658  */
17659 void
17660 clutter_actor_set_easing_delay (ClutterActor *self,
17661                                 guint         msecs)
17662 {
17663   ClutterAnimationInfo *info;
17664
17665   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17666
17667   info = _clutter_actor_get_animation_info (self);
17668
17669   if (info->cur_state == NULL)
17670     {
17671       g_warning ("You must call clutter_actor_save_easing_state() prior "
17672                  "to calling clutter_actor_set_easing_delay().");
17673       return;
17674     }
17675
17676   if (info->cur_state->easing_delay != msecs)
17677     info->cur_state->easing_delay = msecs;
17678 }
17679
17680 /**
17681  * clutter_actor_get_easing_delay:
17682  * @self: a #ClutterActor
17683  *
17684  * Retrieves the delay that should be applied when tweening animatable
17685  * properties.
17686  *
17687  * Return value: a delay, in milliseconds
17688  *
17689  * Since: 1.10
17690  */
17691 guint
17692 clutter_actor_get_easing_delay (ClutterActor *self)
17693 {
17694   const ClutterAnimationInfo *info;
17695
17696   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17697
17698   info = _clutter_actor_get_animation_info_or_defaults (self);
17699
17700   if (info->cur_state != NULL)
17701     return info->cur_state->easing_delay;
17702
17703   return 0;
17704 }
17705
17706 /**
17707  * clutter_actor_get_transition:
17708  * @self: a #ClutterActor
17709  * @name: the name of the transition
17710  *
17711  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17712  * transition @name.
17713  *
17714  * Transitions created for animatable properties use the name of the
17715  * property itself, for instance the code below:
17716  *
17717  * |[
17718  *   clutter_actor_set_easing_duration (actor, 1000);
17719  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17720  *
17721  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17722  *   g_signal_connect (transition, "completed",
17723  *                     G_CALLBACK (on_transition_complete),
17724  *                     actor);
17725  * ]|
17726  *
17727  * will call the <function>on_transition_complete</function> callback when
17728  * the transition is complete.
17729  *
17730  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17731  *   was found to match the passed name; the returned instance is owned
17732  *   by Clutter and it should not be freed
17733  *
17734  * Since: 1.10
17735  */
17736 ClutterTransition *
17737 clutter_actor_get_transition (ClutterActor *self,
17738                               const char   *name)
17739 {
17740   TransitionClosure *clos;
17741   const ClutterAnimationInfo *info;
17742
17743   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17744   g_return_val_if_fail (name != NULL, NULL);
17745
17746   info = _clutter_actor_get_animation_info_or_defaults (self);
17747   if (info->transitions == NULL)
17748     return NULL;
17749
17750   clos = g_hash_table_lookup (info->transitions, name);
17751   if (clos == NULL)
17752     return NULL;
17753
17754   return clos->transition;
17755 }
17756
17757 /**
17758  * clutter_actor_save_easing_state:
17759  * @self: a #ClutterActor
17760  *
17761  * Saves the current easing state for animatable properties, and creates
17762  * a new state with the default values for easing mode and duration.
17763  *
17764  * Since: 1.10
17765  */
17766 void
17767 clutter_actor_save_easing_state (ClutterActor *self)
17768 {
17769   ClutterAnimationInfo *info;
17770   AState new_state;
17771
17772   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17773
17774   info = _clutter_actor_get_animation_info (self);
17775
17776   if (info->states == NULL)
17777     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17778
17779   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17780   new_state.easing_duration = 250;
17781   new_state.easing_delay = 0;
17782
17783   g_array_append_val (info->states, new_state);
17784
17785   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17786 }
17787
17788 /**
17789  * clutter_actor_restore_easing_state:
17790  * @self: a #ClutterActor
17791  *
17792  * Restores the easing state as it was prior to a call to
17793  * clutter_actor_save_easing_state().
17794  *
17795  * Since: 1.10
17796  */
17797 void
17798 clutter_actor_restore_easing_state (ClutterActor *self)
17799 {
17800   ClutterAnimationInfo *info;
17801
17802   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17803
17804   info = _clutter_actor_get_animation_info (self);
17805
17806   if (info->states == NULL)
17807     {
17808       g_critical ("The function clutter_actor_restore_easing_state() has "
17809                   "called without a previous call to "
17810                   "clutter_actor_save_easing_state().");
17811       return;
17812     }
17813
17814   g_array_remove_index (info->states, info->states->len - 1);
17815
17816   if (info->states->len > 0)
17817     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17818   else
17819     {
17820       g_array_unref (info->states);
17821       info->states = NULL;
17822       info->cur_state = NULL;
17823     }
17824 }
17825
17826 /**
17827  * clutter_actor_set_content:
17828  * @self: a #ClutterActor
17829  * @content: (allow-none): a #ClutterContent, or %NULL
17830  *
17831  * Sets the contents of a #ClutterActor.
17832  *
17833  * Since: 1.10
17834  */
17835 void
17836 clutter_actor_set_content (ClutterActor   *self,
17837                            ClutterContent *content)
17838 {
17839   ClutterActorPrivate *priv;
17840
17841   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17842   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17843
17844   priv = self->priv;
17845
17846   if (priv->content != NULL)
17847     {
17848       _clutter_content_detached (priv->content, self);
17849       g_clear_object (&priv->content);
17850     }
17851
17852   priv->content = content;
17853
17854   if (priv->content != NULL)
17855     {
17856       g_object_ref (priv->content);
17857       _clutter_content_attached (priv->content, self);
17858     }
17859
17860   /* given that the content is always painted within the allocation,
17861    * we only need to queue a redraw here
17862    */
17863   clutter_actor_queue_redraw (self);
17864
17865   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17866
17867   /* if the content gravity is not resize-fill, and the new content has a
17868    * different preferred size than the previous one, then the content box
17869    * may have been changed. since we compute that lazily, we just notify
17870    * here, and let whomever watches :content-box do whatever they need to
17871    * do.
17872    */
17873   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17874     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17875 }
17876
17877 /**
17878  * clutter_actor_get_content:
17879  * @self: a #ClutterActor
17880  *
17881  * Retrieves the contents of @self.
17882  *
17883  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17884  *   or %NULL if none was set
17885  *
17886  * Since: 1.10
17887  */
17888 ClutterContent *
17889 clutter_actor_get_content (ClutterActor *self)
17890 {
17891   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17892
17893   return self->priv->content;
17894 }
17895
17896 /**
17897  * clutter_actor_set_content_gravity:
17898  * @self: a #ClutterActor
17899  * @gravity: the #ClutterContentGravity
17900  *
17901  * Sets the gravity of the #ClutterContent used by @self.
17902  *
17903  * See the description of the #ClutterActor:content-gravity property for
17904  * more information.
17905  *
17906  * The #ClutterActor:content-gravity property is animatable.
17907  *
17908  * Since: 1.10
17909  */
17910 void
17911 clutter_actor_set_content_gravity (ClutterActor *self,
17912                                    ClutterContentGravity  gravity)
17913 {
17914   ClutterActorPrivate *priv;
17915
17916   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17917
17918   priv = self->priv;
17919
17920   if (priv->content_gravity == gravity)
17921     return;
17922
17923   priv->content_box_valid = FALSE;
17924
17925   if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17926     {
17927       ClutterActorBox from_box, to_box;
17928
17929       clutter_actor_get_content_box (self, &from_box);
17930
17931       priv->content_gravity = gravity;
17932
17933       clutter_actor_get_content_box (self, &to_box);
17934
17935       _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17936                                         &from_box,
17937                                         &to_box);
17938     }
17939   else
17940     {
17941       ClutterActorBox to_box;
17942
17943       priv->content_gravity = gravity;
17944
17945       clutter_actor_get_content_box (self, &to_box);
17946
17947       _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17948                                         &to_box);
17949     }
17950
17951   clutter_actor_queue_redraw (self);
17952
17953   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17954 }
17955
17956 /**
17957  * clutter_actor_get_content_gravity:
17958  * @self: a #ClutterActor
17959  *
17960  * Retrieves the content gravity as set using
17961  * clutter_actor_get_content_gravity().
17962  *
17963  * Return value: the content gravity
17964  *
17965  * Since: 1.10
17966  */
17967 ClutterContentGravity
17968 clutter_actor_get_content_gravity (ClutterActor *self)
17969 {
17970   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17971                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17972
17973   return self->priv->content_gravity;
17974 }
17975
17976 /**
17977  * clutter_actor_get_content_box:
17978  * @self: a #ClutterActor
17979  * @box: (out caller-allocates): the return location for the bounding
17980  *   box for the #ClutterContent
17981  *
17982  * Retrieves the bounding box for the #ClutterContent of @self.
17983  *
17984  * The bounding box is relative to the actor's allocation.
17985  *
17986  * If no #ClutterContent is set for @self, or if @self has not been
17987  * allocated yet, then the result is undefined.
17988  *
17989  * The content box is guaranteed to be, at most, as big as the allocation
17990  * of the #ClutterActor.
17991  *
17992  * If the #ClutterContent used by the actor has a preferred size, then
17993  * it is possible to modify the content box by using the
17994  * #ClutterActor:content-gravity property.
17995  *
17996  * Since: 1.10
17997  */
17998 void
17999 clutter_actor_get_content_box (ClutterActor    *self,
18000                                ClutterActorBox *box)
18001 {
18002   ClutterActorPrivate *priv;
18003   gfloat content_w, content_h;
18004   gfloat alloc_w, alloc_h;
18005
18006   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18007   g_return_if_fail (box != NULL);
18008
18009   priv = self->priv;
18010
18011   box->x1 = 0.f;
18012   box->y1 = 0.f;
18013   box->x2 = priv->allocation.x2 - priv->allocation.x1;
18014   box->y2 = priv->allocation.y2 - priv->allocation.y1;
18015
18016   if (priv->content_box_valid)
18017     {
18018       *box = priv->content_box;
18019       return;
18020     }
18021
18022   /* no need to do any more work */
18023   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18024     return;
18025
18026   if (priv->content == NULL)
18027     return;
18028
18029   /* if the content does not have a preferred size then there is
18030    * no point in computing the content box
18031    */
18032   if (!clutter_content_get_preferred_size (priv->content,
18033                                            &content_w,
18034                                            &content_h))
18035     return;
18036
18037   alloc_w = box->x2;
18038   alloc_h = box->y2;
18039
18040   switch (priv->content_gravity)
18041     {
18042     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
18043       box->x2 = box->x1 + MIN (content_w, alloc_w);
18044       box->y2 = box->y1 + MIN (content_h, alloc_h);
18045       break;
18046
18047     case CLUTTER_CONTENT_GRAVITY_TOP:
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       box->y2 = box->y1 + MIN (content_h, alloc_h);
18054       break;
18055
18056     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
18057       if (alloc_w > content_w)
18058         {
18059           box->x1 += (alloc_w - content_w);
18060           box->x2 = box->x1 + content_w;
18061         }
18062       box->y2 = box->y1 + MIN (content_h, alloc_h);
18063       break;
18064
18065     case CLUTTER_CONTENT_GRAVITY_LEFT:
18066       box->x2 = box->x1 + MIN (content_w, alloc_w);
18067       if (alloc_h > content_h)
18068         {
18069           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18070           box->y2 = box->y1 + content_h;
18071         }
18072       break;
18073
18074     case CLUTTER_CONTENT_GRAVITY_CENTER:
18075       if (alloc_w > content_w)
18076         {
18077           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18078           box->x2 = box->x1 + content_w;
18079         }
18080       if (alloc_h > content_h)
18081         {
18082           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18083           box->y2 = box->y1 + content_h;
18084         }
18085       break;
18086
18087     case CLUTTER_CONTENT_GRAVITY_RIGHT:
18088       if (alloc_w > content_w)
18089         {
18090           box->x1 += (alloc_w - content_w);
18091           box->x2 = box->x1 + content_w;
18092         }
18093       if (alloc_h > content_h)
18094         {
18095           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18096           box->y2 = box->y1 + content_h;
18097         }
18098       break;
18099
18100     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18101       box->x2 = box->x1 + MIN (content_w, alloc_w);
18102       if (alloc_h > content_h)
18103         {
18104           box->y1 += (alloc_h - content_h);
18105           box->y2 = box->y1 + content_h;
18106         }
18107       break;
18108
18109     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18110       if (alloc_w > content_w)
18111         {
18112           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18113           box->x2 = box->x1 + content_w;
18114         }
18115       if (alloc_h > content_h)
18116         {
18117           box->y1 += (alloc_h - content_h);
18118           box->y2 = box->y1 + content_h;
18119         }
18120       break;
18121
18122     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18123       if (alloc_w > content_w)
18124         {
18125           box->x1 += (alloc_w - content_w);
18126           box->x2 = box->x1 + content_w;
18127         }
18128       if (alloc_h > content_h)
18129         {
18130           box->y1 += (alloc_h - content_h);
18131           box->y2 = box->y1 + content_h;
18132         }
18133       break;
18134
18135     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18136       g_assert_not_reached ();
18137       break;
18138
18139     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18140       {
18141         double r_c = content_w / content_h;
18142         double r_a = alloc_w / alloc_h;
18143
18144         if (r_c >= 1.0)
18145           {
18146             if (r_a >= 1.0)
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             else
18155               {
18156                 box->y1 = 0.f;
18157                 box->y2 = alloc_h;
18158
18159                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18160                 box->x2 = box->x1 + (alloc_h * r_c);
18161               }
18162           }
18163         else
18164           {
18165             if (r_a >= 1.0)
18166               {
18167                 box->y1 = 0.f;
18168                 box->y2 = alloc_h;
18169
18170                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18171                 box->x2 = box->x1 + (alloc_h * r_c);
18172               }
18173             else
18174               {
18175                 box->x1 = 0.f;
18176                 box->x2 = alloc_w;
18177
18178                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18179                 box->y2 = box->y1 + (alloc_w * r_c);
18180               }
18181           }
18182       }
18183       break;
18184     }
18185 }
18186
18187 /**
18188  * clutter_actor_set_content_scaling_filters:
18189  * @self: a #ClutterActor
18190  * @min_filter: the minification filter for the content
18191  * @mag_filter: the magnification filter for the content
18192  *
18193  * Sets the minification and magnification filter to be applied when
18194  * scaling the #ClutterActor:content of a #ClutterActor.
18195  *
18196  * The #ClutterActor:minification-filter will be used when reducing
18197  * the size of the content; the #ClutterActor:magnification-filter
18198  * will be used when increasing the size of the content.
18199  *
18200  * Since: 1.10
18201  */
18202 void
18203 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18204                                            ClutterScalingFilter  min_filter,
18205                                            ClutterScalingFilter  mag_filter)
18206 {
18207   ClutterActorPrivate *priv;
18208   gboolean changed;
18209   GObject *obj;
18210
18211   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18212
18213   priv = self->priv;
18214   obj = G_OBJECT (self);
18215
18216   g_object_freeze_notify (obj);
18217
18218   changed = FALSE;
18219
18220   if (priv->min_filter != min_filter)
18221     {
18222       priv->min_filter = min_filter;
18223       changed = TRUE;
18224
18225       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18226     }
18227
18228   if (priv->mag_filter != mag_filter)
18229     {
18230       priv->mag_filter = mag_filter;
18231       changed = TRUE;
18232
18233       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18234     }
18235
18236   if (changed)
18237     clutter_actor_queue_redraw (self);
18238
18239   g_object_thaw_notify (obj);
18240 }
18241
18242 /**
18243  * clutter_actor_get_content_scaling_filters:
18244  * @self: a #ClutterActor
18245  * @min_filter: (out) (allow-none): return location for the minification
18246  *   filter, or %NULL
18247  * @mag_filter: (out) (allow-none): return location for the magnification
18248  *   filter, or %NULL
18249  *
18250  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18251  *
18252  * Since: 1.10
18253  */
18254 void
18255 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18256                                            ClutterScalingFilter *min_filter,
18257                                            ClutterScalingFilter *mag_filter)
18258 {
18259   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18260
18261   if (min_filter != NULL)
18262     *min_filter = self->priv->min_filter;
18263
18264   if (mag_filter != NULL)
18265     *mag_filter = self->priv->mag_filter;
18266 }
18267
18268 /*
18269  * clutter_actor_queue_compute_expand:
18270  * @self: a #ClutterActor
18271  *
18272  * Invalidates the needs_x_expand and needs_y_expand flags on @self
18273  * and its parents up to the top-level actor.
18274  *
18275  * This function also queues a relayout if anything changed.
18276  */
18277 static inline void
18278 clutter_actor_queue_compute_expand (ClutterActor *self)
18279 {
18280   ClutterActor *parent;
18281   gboolean changed;
18282
18283   if (self->priv->needs_compute_expand)
18284     return;
18285
18286   changed = FALSE;
18287   parent = self;
18288   while (parent != NULL)
18289     {
18290       if (!parent->priv->needs_compute_expand)
18291         {
18292           parent->priv->needs_compute_expand = TRUE;
18293           changed = TRUE;
18294         }
18295
18296       parent = parent->priv->parent;
18297     }
18298
18299   if (changed)
18300     clutter_actor_queue_relayout (self);
18301 }
18302
18303 /**
18304  * clutter_actor_set_x_expand:
18305  * @self: a #ClutterActor
18306  * @expand: whether the actor should expand horizontally
18307  *
18308  * Sets whether a #ClutterActor should expand horizontally; this means
18309  * that layout manager should allocate extra space for the actor, if
18310  * possible.
18311  *
18312  * Setting an actor to expand will also make all its parent expand, so
18313  * that it's possible to build an actor tree and only set this flag on
18314  * its leaves and not on every single actor.
18315  *
18316  * Since: 1.12
18317  */
18318 void
18319 clutter_actor_set_x_expand (ClutterActor *self,
18320                             gboolean      expand)
18321 {
18322   ClutterLayoutInfo *info;
18323
18324   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18325
18326   expand = !!expand;
18327
18328   info = _clutter_actor_get_layout_info (self);
18329   if (info->x_expand != expand)
18330     {
18331       info->x_expand = expand;
18332
18333       self->priv->x_expand_set = TRUE;
18334
18335       clutter_actor_queue_compute_expand (self);
18336
18337       g_object_notify_by_pspec (G_OBJECT (self),
18338                                 obj_props[PROP_X_EXPAND]);
18339     }
18340 }
18341
18342 /**
18343  * clutter_actor_get_x_expand:
18344  * @self: a #ClutterActor
18345  *
18346  * Retrieves the value set with clutter_actor_set_x_expand().
18347  *
18348  * See also: clutter_actor_needs_expand()
18349  *
18350  * Return value: %TRUE if the actor has been set to expand
18351  *
18352  * Since: 1.12
18353  */
18354 gboolean
18355 clutter_actor_get_x_expand (ClutterActor *self)
18356 {
18357   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18358
18359   return _clutter_actor_get_layout_info_or_defaults (self)->x_expand;
18360 }
18361
18362 /**
18363  * clutter_actor_set_y_expand:
18364  * @self: a #ClutterActor
18365  * @expand: whether the actor should expand vertically
18366  *
18367  * Sets whether a #ClutterActor should expand horizontally; this means
18368  * that layout manager should allocate extra space for the actor, if
18369  * possible.
18370  *
18371  * Setting an actor to expand will also make all its parent expand, so
18372  * that it's possible to build an actor tree and only set this flag on
18373  * its leaves and not on every single actor.
18374  *
18375  * Since: 1.12
18376  */
18377 void
18378 clutter_actor_set_y_expand (ClutterActor *self,
18379                             gboolean      expand)
18380 {
18381   ClutterLayoutInfo *info;
18382
18383   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18384
18385   expand = !!expand;
18386
18387   info = _clutter_actor_get_layout_info (self);
18388   if (info->y_expand != expand)
18389     {
18390       info->y_expand = expand;
18391
18392       self->priv->y_expand_set = TRUE;
18393
18394       clutter_actor_queue_compute_expand (self);
18395
18396       g_object_notify_by_pspec (G_OBJECT (self),
18397                                 obj_props[PROP_Y_EXPAND]);
18398     }
18399 }
18400
18401 /**
18402  * clutter_actor_get_y_expand:
18403  * @self: a #ClutterActor
18404  *
18405  * Retrieves the value set with clutter_actor_set_y_expand().
18406  *
18407  * See also: clutter_actor_needs_expand()
18408  *
18409  * Return value: %TRUE if the actor has been set to expand
18410  *
18411  * Since: 1.12
18412  */
18413 gboolean
18414 clutter_actor_get_y_expand (ClutterActor *self)
18415 {
18416   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18417
18418   return _clutter_actor_get_layout_info_or_defaults (self)->y_expand;
18419 }
18420
18421 static void
18422 clutter_actor_compute_expand_recursive (ClutterActor *self,
18423                                         gboolean     *x_expand_p,
18424                                         gboolean     *y_expand_p)
18425 {
18426   ClutterActorIter iter;
18427   ClutterActor *child;
18428   gboolean x_expand, y_expand;
18429
18430   x_expand = y_expand = FALSE;
18431
18432   /* note that we don't recurse into children if we're already set to expand;
18433    * this avoids traversing the whole actor tree, even if it may lead to some
18434    * child left with the needs_compute_expand flag set.
18435    */
18436   clutter_actor_iter_init (&iter, self);
18437   while (clutter_actor_iter_next (&iter, &child))
18438     {
18439       x_expand = x_expand ||
18440         clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL);
18441
18442       y_expand = y_expand ||
18443         clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL);
18444     }
18445
18446   *x_expand_p = x_expand;
18447   *y_expand_p = y_expand;
18448 }
18449
18450 static void
18451 clutter_actor_compute_expand (ClutterActor *self)
18452 {
18453   if (self->priv->needs_compute_expand)
18454     {
18455       const ClutterLayoutInfo *info;
18456       gboolean x_expand, y_expand;
18457
18458       info = _clutter_actor_get_layout_info_or_defaults (self);
18459
18460       if (self->priv->x_expand_set)
18461         x_expand = info->x_expand;
18462       else
18463         x_expand = FALSE;
18464
18465       if (self->priv->y_expand_set)
18466         y_expand = info->y_expand;
18467       else
18468         y_expand = FALSE;
18469
18470       /* we don't need to recurse down to the children if the
18471        * actor has been forcibly set to expand
18472        */
18473       if (!(self->priv->x_expand_set && self->priv->y_expand_set))
18474         {
18475           if (self->priv->n_children != 0)
18476             {
18477               gboolean *x_expand_p, *y_expand_p;
18478               gboolean ignored = FALSE;
18479
18480               x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand;
18481               y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand;
18482
18483               clutter_actor_compute_expand_recursive (self,
18484                                                       x_expand_p,
18485                                                       y_expand_p);
18486             }
18487         }
18488
18489       self->priv->needs_compute_expand = FALSE;
18490       self->priv->needs_x_expand = (x_expand != FALSE);
18491       self->priv->needs_y_expand = (y_expand != FALSE);
18492     }
18493 }
18494
18495 /**
18496  * clutter_actor_needs_expand:
18497  * @self: a #ClutterActor
18498  * @orientation: the direction of expansion
18499  *
18500  * Checks whether an actor, or any of its children, is set to expand
18501  * horizontally or vertically.
18502  *
18503  * This function should only be called by layout managers that can
18504  * assign extra space to their children.
18505  *
18506  * If you want to know whether the actor was explicitly set to expand,
18507  * use clutter_actor_get_x_expand() or clutter_actor_get_y_expand().
18508  *
18509  * Return value: %TRUE if the actor should expand
18510  *
18511  * Since: 1.12
18512  */
18513 gboolean
18514 clutter_actor_needs_expand (ClutterActor       *self,
18515                             ClutterOrientation  orientation)
18516 {
18517   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18518
18519   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18520     return FALSE;
18521
18522   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18523     return FALSE;
18524
18525   clutter_actor_compute_expand (self);
18526
18527   switch (orientation)
18528     {
18529     case CLUTTER_ORIENTATION_HORIZONTAL:
18530       return self->priv->needs_x_expand;
18531
18532     case CLUTTER_ORIENTATION_VERTICAL:
18533       return self->priv->needs_y_expand;
18534     }
18535
18536   return FALSE;
18537 }