actor: Finally fix RESIZE_ASPECT content gravity
[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="../../../../examples/basic-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-painting">
119  *   <title>Painting an actor</title>
120  *   <para>There are three ways to paint an actor:</para>
121  *   <itemizedlist>
122  *     <listitem><para>set a delegate #ClutterContent as the value for the
123  *     #ClutterActor:content property of the actor;</para></listitem>
124  *     <listitem><para>subclass #ClutterActor and override the
125  *     #ClutterActorClass.paint_node() virtual function;</para></listitem>
126  *     <listitem><para>subclass #ClutterActor and override the
127  *     #ClutterActorClass.paint() virtual function.</para></listitem>
128  *   </itemizedlist>
129  *   <formalpara>
130  *     <title>Setting the Content property</title>
131  *     <para>A #ClutterContent is a delegate object that takes over the
132  *     painting operation of one, or more actors. The #ClutterContent
133  *     painting will be performed on top of the #ClutterActor:background-color
134  *     of the actor, and before calling the #ClutterActorClass.paint_node()
135  *     virtual function.</para>
136  *     <informalexample><programlisting>
137  * ClutterActor *actor = clutter_actor_new ();
138  *
139  * /&ast; set the bounding box &ast;/
140  * clutter_actor_set_position (actor, 50, 50);
141  * clutter_actor_set_size (actor, 100, 100);
142  *
143  * /&ast; set the content; the image_content variable is set elsewhere &ast;/
144  * clutter_actor_set_content (actor, image_content);
145  *     </programlisting></informalexample>
146  *   </formalpara>
147  *   <formalpara>
148  *     <title>Overriding the paint_node virtual function</title>
149  *     <para>The #ClutterActorClass.paint_node() virtual function is invoked
150  *     whenever an actor needs to be painted. The implementation of the
151  *     virtual function must only paint the contents of the actor itself,
152  *     and not the contents of its children, if the actor has any.</para>
153  *     <para>The #ClutterPaintNode passed to the virtual function is the
154  *     local root of the render tree; any node added to it will be
155  *     rendered at the correct position, as defined by the actor's
156  *     #ClutterActor:allocation.</para>
157  *     <informalexample><programlisting>
158  * static void
159  * my_actor_paint_node (ClutterActor     *actor,
160  *                      ClutterPaintNode *root)
161  * {
162  *   ClutterPaintNode *node;
163  *   ClutterActorBox box;
164  *
165  *   /&ast; where the content of the actor should be painted &ast;/
166  *   clutter_actor_get_allocation_box (actor, &box);
167  *
168  *   /&ast; the cogl_texture variable is set elsewhere &ast;/
169  *   node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170  *                                    CLUTTER_SCALING_FILTER_TRILINEAR,
171  *                                    CLUTTER_SCALING_FILTER_LINEAR);
172  *
173  *   /&ast; paint the content of the node using the allocation &ast;/
174  *   clutter_paint_node_add_rectangle (node, &box);
175  *
176  *   /&ast; add the node, and transfer ownership &ast;/
177  *   clutter_paint_node_add_child (root, node);
178  *   clutter_paint_node_unref (node);
179  * }
180  *     </programlisting></informalexample>
181  *   </formalpara>
182  *   <formalpara>
183  *     <title>Overriding the paint virtual function</title>
184  *     <para>The #ClutterActorClass.paint() virtual function is invoked
185  *     when the #ClutterActor::paint signal is emitted, and after the other
186  *     signal handlers have been invoked. Overriding the paint virtual
187  *     function gives total control to the paint sequence of the actor
188  *     itself, including the children of the actor, if any.</para>
189  *     <warning><para>It is strongly discouraged to override the
190  *     #ClutterActorClass.paint() virtual function, as well as connecting
191  *     to the #ClutterActor::paint signal. These hooks into the paint
192  *     sequence are considered legacy, and will be removed when the Clutter
193  *     API changes.</para></warning>
194  *   </formalpara>
195  * </refsect2>
196  *
197  * <refsect2 id="ClutterActor-events">
198  *   <title>Handling events on an actor</title>
199  *   <para>A #ClutterActor can receive and handle input device events, for
200  *   instance pointer events and key events, as long as its
201  *   #ClutterActor:reactive property is set to %TRUE.</para>
202  *   <para>Once an actor has been determined to be the source of an event,
203  *   Clutter will traverse the scene graph from the top-level actor towards the
204  *   event source, emitting the #ClutterActor::captured-event signal on each
205  *   ancestor until it reaches the source; this phase is also called
206  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
207  *   stopped, the graph is walked backwards, from the source actor to the
208  *   top-level, and the #ClutterActor::event signal, along with other event
209  *   signals if needed, is emitted; this phase is also called <emphasis>the
210  *   bubble phase</emphasis>. At any point of the signal emission, signal
211  *   handlers can stop the propagation through the scene graph by returning
212  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
214  * </refsect2>
215  *
216  * <refsect2 id="ClutterActor-animation">
217  *   <title>Animation</title>
218  *   <para>Animation is a core concept of modern user interfaces; Clutter
219  *   provides a complete and powerful animation framework that automatically
220  *   tweens the actor's state without requiring direct, frame by frame
221  *   manipulation from your application code.</para>
222  *   <formalpara>
223  *     <title>Implicit animations</title>
224  *     <para>The implicit animation model of Clutter assumes that all the
225  *     changes in an actor state should be gradual and asynchronous; Clutter
226  *     will automatically transition an actor's property change between the
227  *     current state and the desired one without manual intervention.</para>
228  *     <para>By default, in the 1.0 API series, the transition happens with
229  *     a duration of zero milliseconds, and the implicit animation is an
230  *     opt in feature to retain backwards compatibility. In order to enable
231  *     implicit animations, it is necessary to change the easing state of
232  *     an actor by using clutter_actor_save_easing_state():</para>
233  *     <informalexample><programlisting>
234  * /&ast; assume that the actor is currently positioned at (100, 100) &ast;/
235  * clutter_actor_save_easing_state (actor);
236  * clutter_actor_set_position (actor, 500, 500);
237  * clutter_actor_restore_easing_state (actor);
238  *     </programlisting></informalexample>
239  *     <para>The example above will trigger an implicit animation of the
240  *     actor between its current position to a new position.</para>
241  *     <para>It is possible to animate multiple properties of an actor
242  *     at the same time, and you can animate multiple actors at the same
243  *     time as well, for instance:</para>
244  *     <informalexample><programlisting>
245  * /&ast; animate the actor's opacity and depth &ast;/
246  * clutter_actor_save_easing_state (actor);
247  * clutter_actor_set_opacity (actor, 0);
248  * clutter_actor_set_depth (actor, -100);
249  * clutter_actor_restore_easing_state (actor);
250  *
251  * /&ast; animate another actor's opacity &ast;/
252  * clutter_actor_save_easing_state (another_actor);
253  * clutter_actor_set_opacity (another_actor, 255);
254  * clutter_actor_set_depth (another_actor, 100);
255  * clutter_actor_restore_easing_state (another_actor);
256  *     </programlisting></informalexample>
257  *     <para>Implicit animations use a default duration of 250 milliseconds,
258  *     and a default easing mode of %CLUTTER_EASE_OUT_CUBIC, unless you call
259  *     clutter_actor_set_easing_mode() and clutter_actor_set_easing_duration()
260  *     after changing the easing state of the actor.</para>
261  *     <para>It is important to note that if you modify the state on an
262  *     animatable property while a transition is in flight, the transition's
263  *     final value will be updated, as well as its duration and progress
264  *     mode by using the current easing state; for instance, in the following
265  *     example:</para>
266  *     <informalexample><programlisting>
267  * clutter_actor_save_easing_state (actor);
268  * clutter_actor_set_x (actor, 200);
269  * clutter_actor_restore_easing_state (actor);
270  *
271  * clutter_actor_save_easing_state (actor);
272  * clutter_actor_set_x (actor, 100);
273  * clutter_actor_restore_easing_state (actor);
274  *     </programlisting></informalexample>
275  *     <para>the first call to clutter_actor_set_x() will begin a transition
276  *     of the #ClutterActor:x property to the value of 200; the second call
277  *     to clutter_actor_set_x() will change the transition's final value to
278  *     100.</para>
279  *     <para>It is possible to retrieve the #ClutterTransition used by the
280  *     animatable properties by using clutter_actor_get_transition() and using
281  *     the property name as the transition name.</para>
282  *   </formalpara>
283  *   <formalpara>
284  *     <title>Explicit animations</title>
285  *     <para>The explicit animation model supported by Clutter requires that
286  *     you create a #ClutterTransition object, and set the initial and
287  *     final values. The transition will not start unless you add it to the
288  *     #ClutterActor.</para>
289  *     <informalexample><programlisting>
290  * ClutterTransition *transition;
291  *
292  * transition = clutter_property_transition_new ("opacity");
293  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000);
294  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
295  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
296  * clutter_transition_set_from (transition, G_TYPE_UINT, 255);
297  * clutter_transition_set_to (transition, G_TYPE_UINT, 0);
298  *
299  * clutter_actor_add_transition (actor, "animate-opacity", transition);
300  *     </programlisting></informalexample>
301  *     <para>The example above will animate the #ClutterActor:opacity property
302  *     of an actor between fully opaque and fully transparent, and back, over
303  *     a span of 3 seconds. The animation does not begin until it is added to
304  *     the actor.</para>
305  *     <para>The explicit animation API should also be used when using custom
306  *     animatable properties for #ClutterAction, #ClutterConstraint, and
307  *     #ClutterEffect instances associated to an actor; see the section on
308  *     <ulink linkend="ClutterActor-custom-animatable-properties">custom
309  *     animatable properties below</ulink> for an example.</para>
310  *     <para>Finally, explicit animations are useful for creating animations
311  *     that run continuously, for instance:</para>
312  *     <informalexample><programlisting>
313  * /&ast; this animation will pulse the actor's opacity continuously &ast;/
314  * ClutterTransition *transition;
315  * ClutterInterval *interval;
316  *
317  * transition = clutter_property_transition_new ("opacity");
318  *
319  * /&ast; we want to animate the opacity between 0 and 255 &ast;/
320  * clutter_transition_set_from (transition, G_TYPE_UINT, 0);
321  * clutter_transition_set_to (transition, G_TYPE_UINT, 255);
322  *
323  * /&ast; over a one second duration, running an infinite amount of times &ast;/
324  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
325  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
326  *
327  * /&ast; we want to fade in and out, so we need to auto-reverse the transition &ast;/
328  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
329  *
330  * /&ast; and we want to use an easing function that eases both in and out &ast;/
331  * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
332  *                                     CLUTTER_EASE_IN_OUT_CUBIC);
333  *
334  * /&ast; add the transition to the desired actor; this will
335  *  &ast; start the animation.
336  *  &ast;/
337  * clutter_actor_add_transition (actor, "opacityAnimation", transition);
338  *     </programlisting></informalexample>
339  *   </formalpara>
340  * </refsect2>
341  *
342  * <refsect2 id="ClutterActor-subclassing">
343  *   <title>Implementing an actor</title>
344  *   <para>Careful consideration should be given when deciding to implement
345  *   a #ClutterActor sub-class. It is generally recommended to implement a
346  *   sub-class of #ClutterActor only for actors that should be used as leaf
347  *   nodes of a scene graph.</para>
348  *   <para>If your actor should be painted in a custom way, you should
349  *   override the #ClutterActor::paint signal class handler. You can either
350  *   opt to chain up to the parent class implementation or decide to fully
351  *   override the default paint implementation; Clutter will set up the
352  *   transformations and clip regions prior to emitting the #ClutterActor::paint
353  *   signal.</para>
354  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
355  *   #ClutterActorClass.get_preferred_height() virtual functions it is
356  *   possible to change or provide the preferred size of an actor; similarly,
357  *   by overriding the #ClutterActorClass.allocate() virtual function it is
358  *   possible to control the layout of the children of an actor. Make sure to
359  *   always chain up to the parent implementation of the
360  *   #ClutterActorClass.allocate() virtual function.</para>
361  *   <para>In general, it is strongly encouraged to use delegation and
362  *   composition instead of direct subclassing.</para>
363  * </refsect2>
364  *
365  * <refsect2 id="ClutterActor-script">
366  *   <title>ClutterActor custom properties for #ClutterScript</title>
367  *   <para>#ClutterActor defines a custom "rotation" property which
368  *   allows a short-hand description of the rotations to be applied
369  *   to an actor.</para>
370  *   <para>The syntax of the "rotation" property is the following:</para>
371  *   <informalexample>
372  *     <programlisting>
373  * "rotation" : [
374  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
375  * ]
376  *     </programlisting>
377  *   </informalexample>
378  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
379  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
380  *   floating point value representing the rotation angle on the given axis,
381  *   in degrees.</para>
382  *   <para>The <emphasis>center</emphasis> array is optional, and if present
383  *   it must contain the center of rotation as described by two coordinates:
384  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
385  *   "z-axis".</para>
386  *   <para>#ClutterActor also defines a scriptable "margin" property which
387  *   follows the CSS "margin" shorthand.
388  *   <informalexample>
389  *     <programlisting>
390  * // 4 values
391  * "margin" : [ &lt;top&gt;, &lt;right&gt;, &lt;bottom&gt; &lt;left&gt; ]
392  * // 3 values
393  * "margin" : [ &lt;top&gt;, &lt;left/right&gt;, &lt;bottom&gt; ]
394  * // 2 values
395  * "margin" : [ &lt;top/bottom&gt;, &lt;left/right&gt; ]
396  * // 1 value
397  * "margin" : [ &lt;top/right/bottom/left&gt; ]
398  *     </programlisting>
399  *   </informalexample>
400  *   </para>
401  *   <para>#ClutterActor will also parse every positional and dimensional
402  *   property defined as a string through clutter_units_from_string(); you
403  *   should read the documentation for the #ClutterUnits parser format for
404  *   the valid units and syntax.</para>
405  * </refsect2>
406  *
407  * <refsect2 id="ClutterActor-custom-animatable-properties">
408  *   <title>Custom animatable properties</title>
409  *   <para>#ClutterActor allows accessing properties of #ClutterAction,
410  *   #ClutterEffect, and #ClutterConstraint instances associated to an actor
411  *   instance for animation purposes.</para>
412  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
413  *   property it is necessary to set the #ClutterActorMeta:name property on the
414  *   given action or constraint.</para>
415  *   <para>The property can be accessed using the following syntax:</para>
416  *   <informalexample>
417  *     <programlisting>
418  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
419  *     </programlisting>
420  *   </informalexample>
421  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
422  *   <para>The <emphasis>section</emphasis> fragment can be one between
423  *   "actions", "constraints" and "effects".</para>
424  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
425  *   action or constraint, as specified by the #ClutterActorMeta:name
426  *   property.</para>
427  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
428  *   action or constraint property to be animated.</para>
429  *   <para>The example below animates a #ClutterBindConstraint applied to an
430  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
431  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
432  *   its initial state is overlapping the actor to which is bound to.</para>
433  *   <informalexample><programlisting>
434  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
435  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
436  * clutter_actor_add_constraint (rect, constraint);
437  *
438  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
439  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
440  * clutter_actor_add_constraint (rect, constraint);
441  *
442  * clutter_actor_set_reactive (origin, TRUE);
443  *
444  * g_signal_connect (origin, "button-press-event",
445  *                   G_CALLBACK (on_button_press),
446  *                   rect);
447  *   </programlisting></informalexample>
448  *   <para>On button press, the rectangle "slides" from behind the actor to
449  *   which is bound to, using the #ClutterBindConstraint:offset property to
450  *   achieve the effect:</para>
451  *   <informalexample><programlisting>
452  * gboolean
453  * on_button_press (ClutterActor *origin,
454  *                  ClutterEvent *event,
455  *                  ClutterActor *rect)
456  * {
457  *   ClutterTransition *transition;
458  *   ClutterInterval *interval;
459  *
460  *   /&ast; the offset that we want to apply; this will make the actor
461  *    &ast; slide in from behind the origin and rest at the right of
462  *    &ast; the origin, plus a padding value.
463  *    &ast;/
464  *   float new_offset = clutter_actor_get_width (origin) + h_padding;
465  *
466  *   /&ast; the property we wish to animate; the "@constraints" section
467  *    &ast; tells Clutter to check inside the constraints associated
468  *    &ast; with the actor; the "bind-x" section is the name of the
469  *    &ast; constraint; and the "offset" is the name of the property
470  *    &ast; on the constraint.
471  *    &ast;/
472  *   const char *prop = "@constraints.bind-x.offset";
473  *
474  *   /&ast; create a new transition for the given property &ast;/
475  *   transition = clutter_property_transition_new (prop);
476  *
477  *   /&ast; set the easing mode and duration &ast;/
478  *   clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
479  *                                       CLUTTER_EASE_OUT_CUBIC);
480  *   clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
481  *
482  *   /&ast; create the interval with the initial and final values &ast;/
483  *   interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
484  *   clutter_transition_set_interval (transition, interval);
485  *
486  *   /&ast; add the transition to the actor; this causes the animation
487  *    &ast; to start. the name "offsetAnimation" can be used to retrieve
488  *    &ast; the transition later.
489  *    &ast;/
490  *   clutter_actor_add_transition (rect, "offsetAnimation", transition);
491  *
492  *   /&ast; we handled the event &ast;/
493  *   return CLUTTER_EVENT_STOP;
494  * }
495  *   </programlisting></informalexample>
496  * </refsect2>
497  */
498
499 /**
500  * CLUTTER_ACTOR_IS_MAPPED:
501  * @a: a #ClutterActor
502  *
503  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
504  *
505  * The mapped state is set when the actor is visible and all its parents up
506  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
507  *
508  * This check can be used to see if an actor is going to be painted, as only
509  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
510  *
511  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
512  * not be checked directly; instead, the recommended usage is to connect a
513  * handler on the #GObject::notify signal for the #ClutterActor:mapped
514  * property of #ClutterActor, and check the presence of
515  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
516  *
517  * It is also important to note that Clutter may delay the changes of
518  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
519  * limitations, or during the reparenting of an actor, to optimize
520  * unnecessary (and potentially expensive) state changes.
521  *
522  * Since: 0.2
523  */
524
525 /**
526  * CLUTTER_ACTOR_IS_REALIZED:
527  * @a: a #ClutterActor
528  *
529  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
530  *
531  * The realized state has an actor-dependant interpretation. If an
532  * actor wants to delay allocating resources until it is attached to a
533  * stage, it may use the realize state to do so. However it is
534  * perfectly acceptable for an actor to allocate Cogl resources before
535  * being realized because there is only one drawing context used by Clutter
536  * so any resources will work on any stage.  If an actor is mapped it
537  * must also be realized, but an actor can be realized and unmapped
538  * (this is so hiding an actor temporarily doesn't do an expensive
539  * unrealize/realize).
540  *
541  * To be realized an actor must be inside a stage, and all its parents
542  * must be realized.
543  *
544  * Since: 0.2
545  */
546
547 /**
548  * CLUTTER_ACTOR_IS_VISIBLE:
549  * @a: a #ClutterActor
550  *
551  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
552  * Equivalent to the ClutterActor::visible object property.
553  *
554  * Note that an actor is only painted onscreen if it's mapped, which
555  * means it's visible, and all its parents are visible, and one of the
556  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
557  *
558  * Since: 0.2
559  */
560
561 /**
562  * CLUTTER_ACTOR_IS_REACTIVE:
563  * @a: a #ClutterActor
564  *
565  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
566  *
567  * Only reactive actors will receive event-related signals.
568  *
569  * Since: 0.6
570  */
571
572 #ifdef HAVE_CONFIG_H
573 #include "config.h"
574 #endif
575
576 #include <math.h>
577
578 #include <gobject/gvaluecollector.h>
579
580 #include <cogl/cogl.h>
581
582 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
583 #define CLUTTER_ENABLE_EXPERIMENTAL_API
584
585 #include "clutter-actor-private.h"
586
587 #include "clutter-action.h"
588 #include "clutter-actor-meta-private.h"
589 #include "clutter-animatable.h"
590 #include "clutter-color-static.h"
591 #include "clutter-color.h"
592 #include "clutter-constraint.h"
593 #include "clutter-container.h"
594 #include "clutter-content-private.h"
595 #include "clutter-debug.h"
596 #include "clutter-effect-private.h"
597 #include "clutter-enum-types.h"
598 #include "clutter-fixed-layout.h"
599 #include "clutter-flatten-effect.h"
600 #include "clutter-interval.h"
601 #include "clutter-main.h"
602 #include "clutter-marshal.h"
603 #include "clutter-paint-nodes.h"
604 #include "clutter-paint-node-private.h"
605 #include "clutter-paint-volume-private.h"
606 #include "clutter-private.h"
607 #include "clutter-profile.h"
608 #include "clutter-property-transition.h"
609 #include "clutter-scriptable.h"
610 #include "clutter-script-private.h"
611 #include "clutter-stage-private.h"
612 #include "clutter-timeline.h"
613 #include "clutter-transition.h"
614 #include "clutter-units.h"
615
616 #include "deprecated/clutter-actor.h"
617 #include "deprecated/clutter-behaviour.h"
618 #include "deprecated/clutter-container.h"
619
620 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
621 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
622
623 /* Internal enum used to control mapped state update.  This is a hint
624  * which indicates when to do something other than just enforce
625  * invariants.
626  */
627 typedef enum {
628   MAP_STATE_CHECK,           /* just enforce invariants. */
629   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
630                               * used when about to unparent.
631                               */
632   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
633                               * used to set mapped on toplevels.
634                               */
635   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
636                               * used just before unmapping parent.
637                               */
638 } MapStateChange;
639
640 /* 3 entries should be a good compromise, few layout managers
641  * will ask for 3 different preferred size in each allocation cycle */
642 #define N_CACHED_SIZE_REQUESTS 3
643
644 struct _ClutterActorPrivate
645 {
646   /* request mode */
647   ClutterRequestMode request_mode;
648
649   /* our cached size requests for different width / height */
650   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
651   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
652
653   /* An age of 0 means the entry is not set */
654   guint cached_height_age;
655   guint cached_width_age;
656
657   /* the bounding box of the actor, relative to the parent's
658    * allocation
659    */
660   ClutterActorBox allocation;
661   ClutterAllocationFlags allocation_flags;
662
663   /* clip, in actor coordinates */
664   cairo_rectangle_t clip;
665
666   /* the cached transformation matrix; see apply_transform() */
667   CoglMatrix transform;
668
669   guint8 opacity;
670   gint opacity_override;
671
672   ClutterOffscreenRedirect offscreen_redirect;
673
674   /* This is an internal effect used to implement the
675      offscreen-redirect property */
676   ClutterEffect *flatten_effect;
677
678   /* scene graph */
679   ClutterActor *parent;
680   ClutterActor *prev_sibling;
681   ClutterActor *next_sibling;
682   ClutterActor *first_child;
683   ClutterActor *last_child;
684
685   gint n_children;
686
687   /* tracks whenever the children of an actor are changed; the
688    * age is incremented by 1 whenever an actor is added or
689    * removed. the age is not incremented when the first or the
690    * last child pointers are changed, or when grandchildren of
691    * an actor are changed.
692    */
693   gint age;
694
695   gchar *name; /* a non-unique name, used for debugging */
696   guint32 id; /* unique id, used for backward compatibility */
697
698   gint32 pick_id; /* per-stage unique id, used for picking */
699
700   /* a back-pointer to the Pango context that we can use
701    * to create pre-configured PangoLayout
702    */
703   PangoContext *pango_context;
704
705   /* the text direction configured for this child - either by
706    * application code, or by the actor's parent
707    */
708   ClutterTextDirection text_direction;
709
710   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
711   gint internal_child;
712
713   /* meta classes */
714   ClutterMetaGroup *actions;
715   ClutterMetaGroup *constraints;
716   ClutterMetaGroup *effects;
717
718   /* delegate object used to allocate the children of this actor */
719   ClutterLayoutManager *layout_manager;
720
721   /* delegate object used to paint the contents of this actor */
722   ClutterContent *content;
723
724   ClutterActorBox content_box;
725   ClutterContentGravity content_gravity;
726   ClutterScalingFilter min_filter;
727   ClutterScalingFilter mag_filter;
728
729   /* used when painting, to update the paint volume */
730   ClutterEffect *current_effect;
731
732   /* This is used to store an effect which needs to be redrawn. A
733      redraw can be queued to start from a particular effect. This is
734      used by parametrised effects that can cache an image of the
735      actor. If a parameter of the effect changes then it only needs to
736      redraw the cached image, not the actual actor. The pointer is
737      only valid if is_dirty == TRUE. If the pointer is NULL then the
738      whole actor is dirty. */
739   ClutterEffect *effect_to_redraw;
740
741   /* This is used when painting effects to implement the
742      clutter_actor_continue_paint() function. It points to the node in
743      the list of effects that is next in the chain */
744   const GList *next_effect_to_paint;
745
746   ClutterPaintVolume paint_volume;
747
748   /* NB: This volume isn't relative to this actor, it is in eye
749    * coordinates so that it can remain valid after the actor changes.
750    */
751   ClutterPaintVolume last_paint_volume;
752
753   ClutterStageQueueRedrawEntry *queue_redraw_entry;
754
755   ClutterColor bg_color;
756
757   /* bitfields */
758
759   /* fixed position and sizes */
760   guint position_set                : 1;
761   guint min_width_set               : 1;
762   guint min_height_set              : 1;
763   guint natural_width_set           : 1;
764   guint natural_height_set          : 1;
765   /* cached request is invalid (implies allocation is too) */
766   guint needs_width_request         : 1;
767   /* cached request is invalid (implies allocation is too) */
768   guint needs_height_request        : 1;
769   /* cached allocation is invalid (request has changed, probably) */
770   guint needs_allocation            : 1;
771   guint show_on_set_parent          : 1;
772   guint has_clip                    : 1;
773   guint clip_to_allocation          : 1;
774   guint enable_model_view_transform : 1;
775   guint enable_paint_unmapped       : 1;
776   guint has_pointer                 : 1;
777   guint propagated_one_redraw       : 1;
778   guint paint_volume_valid          : 1;
779   guint last_paint_volume_valid     : 1;
780   guint in_clone_paint              : 1;
781   guint transform_valid             : 1;
782   /* This is TRUE if anything has queued a redraw since we were last
783      painted. In this case effect_to_redraw will point to an effect
784      the redraw was queued from or it will be NULL if the redraw was
785      queued without an effect. */
786   guint is_dirty                    : 1;
787   guint bg_color_set                : 1;
788   guint content_box_valid           : 1;
789   guint x_expand_set                : 1;
790   guint y_expand_set                : 1;
791   guint needs_compute_expand        : 1;
792   guint needs_x_expand              : 1;
793   guint needs_y_expand              : 1;
794 };
795
796 enum
797 {
798   PROP_0,
799
800   PROP_NAME,
801
802   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
803    * when set they force a size request, when gotten they
804    * get the allocation if the allocation is valid, and the
805    * request otherwise
806    */
807   PROP_X,
808   PROP_Y,
809   PROP_WIDTH,
810   PROP_HEIGHT,
811
812   PROP_POSITION,
813   PROP_SIZE,
814
815   /* Then the rest of these size-related properties are the "actual"
816    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
817    */
818   PROP_FIXED_X,
819   PROP_FIXED_Y,
820
821   PROP_FIXED_POSITION_SET,
822
823   PROP_MIN_WIDTH,
824   PROP_MIN_WIDTH_SET,
825
826   PROP_MIN_HEIGHT,
827   PROP_MIN_HEIGHT_SET,
828
829   PROP_NATURAL_WIDTH,
830   PROP_NATURAL_WIDTH_SET,
831
832   PROP_NATURAL_HEIGHT,
833   PROP_NATURAL_HEIGHT_SET,
834
835   PROP_REQUEST_MODE,
836
837   /* Allocation properties are read-only */
838   PROP_ALLOCATION,
839
840   PROP_DEPTH,
841
842   PROP_CLIP,
843   PROP_HAS_CLIP,
844   PROP_CLIP_TO_ALLOCATION,
845
846   PROP_OPACITY,
847
848   PROP_OFFSCREEN_REDIRECT,
849
850   PROP_VISIBLE,
851   PROP_MAPPED,
852   PROP_REALIZED,
853   PROP_REACTIVE,
854
855   PROP_SCALE_X,
856   PROP_SCALE_Y,
857   PROP_SCALE_CENTER_X,
858   PROP_SCALE_CENTER_Y,
859   PROP_SCALE_GRAVITY,
860
861   PROP_ROTATION_ANGLE_X,
862   PROP_ROTATION_ANGLE_Y,
863   PROP_ROTATION_ANGLE_Z,
864   PROP_ROTATION_CENTER_X,
865   PROP_ROTATION_CENTER_Y,
866   PROP_ROTATION_CENTER_Z,
867   /* This property only makes sense for the z rotation because the
868      others would depend on the actor having a size along the
869      z-axis */
870   PROP_ROTATION_CENTER_Z_GRAVITY,
871
872   PROP_ANCHOR_X,
873   PROP_ANCHOR_Y,
874   PROP_ANCHOR_GRAVITY,
875
876   PROP_SHOW_ON_SET_PARENT,
877
878   PROP_TEXT_DIRECTION,
879   PROP_HAS_POINTER,
880
881   PROP_ACTIONS,
882   PROP_CONSTRAINTS,
883   PROP_EFFECT,
884
885   PROP_LAYOUT_MANAGER,
886
887   PROP_X_EXPAND,
888   PROP_Y_EXPAND,
889   PROP_X_ALIGN,
890   PROP_Y_ALIGN,
891   PROP_MARGIN_TOP,
892   PROP_MARGIN_BOTTOM,
893   PROP_MARGIN_LEFT,
894   PROP_MARGIN_RIGHT,
895
896   PROP_BACKGROUND_COLOR,
897   PROP_BACKGROUND_COLOR_SET,
898
899   PROP_FIRST_CHILD,
900   PROP_LAST_CHILD,
901
902   PROP_CONTENT,
903   PROP_CONTENT_GRAVITY,
904   PROP_CONTENT_BOX,
905   PROP_MINIFICATION_FILTER,
906   PROP_MAGNIFICATION_FILTER,
907
908   PROP_LAST
909 };
910
911 static GParamSpec *obj_props[PROP_LAST];
912
913 enum
914 {
915   SHOW,
916   HIDE,
917   DESTROY,
918   PARENT_SET,
919   KEY_FOCUS_IN,
920   KEY_FOCUS_OUT,
921   PAINT,
922   PICK,
923   REALIZE,
924   UNREALIZE,
925   QUEUE_REDRAW,
926   QUEUE_RELAYOUT,
927   EVENT,
928   CAPTURED_EVENT,
929   BUTTON_PRESS_EVENT,
930   BUTTON_RELEASE_EVENT,
931   SCROLL_EVENT,
932   KEY_PRESS_EVENT,
933   KEY_RELEASE_EVENT,
934   MOTION_EVENT,
935   ENTER_EVENT,
936   LEAVE_EVENT,
937   ALLOCATION_CHANGED,
938   TRANSITIONS_COMPLETED,
939
940   LAST_SIGNAL
941 };
942
943 static guint actor_signals[LAST_SIGNAL] = { 0, };
944
945 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
946 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
947 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
948 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
949
950 /* These setters are all static for now, maybe they should be in the
951  * public API, but they are perhaps obscure enough to leave only as
952  * properties
953  */
954 static void clutter_actor_set_min_width          (ClutterActor *self,
955                                                   gfloat        min_width);
956 static void clutter_actor_set_min_height         (ClutterActor *self,
957                                                   gfloat        min_height);
958 static void clutter_actor_set_natural_width      (ClutterActor *self,
959                                                   gfloat        natural_width);
960 static void clutter_actor_set_natural_height     (ClutterActor *self,
961                                                   gfloat        natural_height);
962 static void clutter_actor_set_min_width_set      (ClutterActor *self,
963                                                   gboolean      use_min_width);
964 static void clutter_actor_set_min_height_set     (ClutterActor *self,
965                                                   gboolean      use_min_height);
966 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
967                                                   gboolean  use_natural_width);
968 static void clutter_actor_set_natural_height_set (ClutterActor *self,
969                                                   gboolean  use_natural_height);
970 static void clutter_actor_update_map_state       (ClutterActor  *self,
971                                                   MapStateChange change);
972 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
973
974 /* Helper routines for managing anchor coords */
975 static void clutter_anchor_coord_get_units (ClutterActor      *self,
976                                             const AnchorCoord *coord,
977                                             gfloat            *x,
978                                             gfloat            *y,
979                                             gfloat            *z);
980 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
981                                             gfloat             x,
982                                             gfloat             y,
983                                             gfloat             z);
984
985 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
986 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
987                                                         ClutterGravity     gravity);
988
989 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
990
991 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
992
993 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
994                                                                ClutterActor *ancestor,
995                                                                CoglMatrix *matrix);
996
997 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
998
999 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
1000
1001 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
1002                                                                 const ClutterColor *color);
1003
1004 static void on_layout_manager_changed (ClutterLayoutManager *manager,
1005                                        ClutterActor         *self);
1006
1007 static inline void clutter_actor_queue_compute_expand (ClutterActor *self);
1008
1009 /* Helper macro which translates by the anchor coord, applies the
1010    given transformation and then translates back */
1011 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
1012   gfloat _tx, _ty, _tz;                                                \
1013   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
1014   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
1015   { _transform; }                                                      \
1016   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
1017
1018 static GQuark quark_shader_data = 0;
1019 static GQuark quark_actor_layout_info = 0;
1020 static GQuark quark_actor_transform_info = 0;
1021 static GQuark quark_actor_animation_info = 0;
1022
1023 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
1024                          clutter_actor,
1025                          G_TYPE_INITIALLY_UNOWNED,
1026                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1027                                                 clutter_container_iface_init)
1028                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1029                                                 clutter_scriptable_iface_init)
1030                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1031                                                 clutter_animatable_iface_init)
1032                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1033                                                 atk_implementor_iface_init));
1034
1035 /*< private >
1036  * clutter_actor_get_debug_name:
1037  * @actor: a #ClutterActor
1038  *
1039  * Retrieves a printable name of @actor for debugging messages
1040  *
1041  * Return value: a string with a printable name
1042  */
1043 const gchar *
1044 _clutter_actor_get_debug_name (ClutterActor *actor)
1045 {
1046   return actor->priv->name != NULL ? actor->priv->name
1047                                    : G_OBJECT_TYPE_NAME (actor);
1048 }
1049
1050 #ifdef CLUTTER_ENABLE_DEBUG
1051 /* XXX - this is for debugging only, remove once working (or leave
1052  * in only in some debug mode). Should leave it for a little while
1053  * until we're confident in the new map/realize/visible handling.
1054  */
1055 static inline void
1056 clutter_actor_verify_map_state (ClutterActor *self)
1057 {
1058   ClutterActorPrivate *priv = self->priv;
1059
1060   if (CLUTTER_ACTOR_IS_REALIZED (self))
1061     {
1062       /* all bets are off during reparent when we're potentially realized,
1063        * but should not be according to invariants
1064        */
1065       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1066         {
1067           if (priv->parent == NULL)
1068             {
1069               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1070                 {
1071                 }
1072               else
1073                 g_warning ("Realized non-toplevel actor '%s' should "
1074                            "have a parent",
1075                            _clutter_actor_get_debug_name (self));
1076             }
1077           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1078             {
1079               g_warning ("Realized actor %s has an unrealized parent %s",
1080                          _clutter_actor_get_debug_name (self),
1081                          _clutter_actor_get_debug_name (priv->parent));
1082             }
1083         }
1084     }
1085
1086   if (CLUTTER_ACTOR_IS_MAPPED (self))
1087     {
1088       if (!CLUTTER_ACTOR_IS_REALIZED (self))
1089         g_warning ("Actor '%s' is mapped but not realized",
1090                    _clutter_actor_get_debug_name (self));
1091
1092       /* remaining bets are off during reparent when we're potentially
1093        * mapped, but should not be according to invariants
1094        */
1095       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1096         {
1097           if (priv->parent == NULL)
1098             {
1099               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1100                 {
1101                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1102                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1103                     {
1104                       g_warning ("Toplevel actor '%s' is mapped "
1105                                  "but not visible",
1106                                  _clutter_actor_get_debug_name (self));
1107                     }
1108                 }
1109               else
1110                 {
1111                   g_warning ("Mapped actor '%s' should have a parent",
1112                              _clutter_actor_get_debug_name (self));
1113                 }
1114             }
1115           else
1116             {
1117               ClutterActor *iter = self;
1118
1119               /* check for the enable_paint_unmapped flag on the actor
1120                * and parents; if the flag is enabled at any point of this
1121                * branch of the scene graph then all the later checks
1122                * become pointless
1123                */
1124               while (iter != NULL)
1125                 {
1126                   if (iter->priv->enable_paint_unmapped)
1127                     return;
1128
1129                   iter = iter->priv->parent;
1130                 }
1131
1132               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1133                 {
1134                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1135                              "is not visible",
1136                              _clutter_actor_get_debug_name (self),
1137                              _clutter_actor_get_debug_name (priv->parent));
1138                 }
1139
1140               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1141                 {
1142                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1143                              "is not realized",
1144                              _clutter_actor_get_debug_name (self),
1145                              _clutter_actor_get_debug_name (priv->parent));
1146                 }
1147
1148               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1149                 {
1150                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1151                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1152                                "parent '%s' is not mapped",
1153                                _clutter_actor_get_debug_name (self),
1154                                _clutter_actor_get_debug_name (priv->parent));
1155                 }
1156             }
1157         }
1158     }
1159 }
1160
1161 #endif /* CLUTTER_ENABLE_DEBUG */
1162
1163 static void
1164 clutter_actor_set_mapped (ClutterActor *self,
1165                           gboolean      mapped)
1166 {
1167   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1168     return;
1169
1170   if (mapped)
1171     {
1172       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1173       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1174     }
1175   else
1176     {
1177       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1178       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1179     }
1180 }
1181
1182 /* this function updates the mapped and realized states according to
1183  * invariants, in the appropriate order.
1184  */
1185 static void
1186 clutter_actor_update_map_state (ClutterActor  *self,
1187                                 MapStateChange change)
1188 {
1189   gboolean was_mapped;
1190
1191   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1192
1193   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1194     {
1195       /* the mapped flag on top-level actors must be set by the
1196        * per-backend implementation because it might be asynchronous.
1197        *
1198        * That is, the MAPPED flag on toplevels currently tracks the X
1199        * server mapped-ness of the window, while the expected behavior
1200        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1201        * This creates some weird complexity by breaking the invariant
1202        * that if we're visible and all ancestors shown then we are
1203        * also mapped - instead, we are mapped if all ancestors
1204        * _possibly excepting_ the stage are mapped. The stage
1205        * will map/unmap for example when it is minimized or
1206        * moved to another workspace.
1207        *
1208        * So, the only invariant on the stage is that if visible it
1209        * should be realized, and that it has to be visible to be
1210        * mapped.
1211        */
1212       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1213         clutter_actor_realize (self);
1214
1215       switch (change)
1216         {
1217         case MAP_STATE_CHECK:
1218           break;
1219
1220         case MAP_STATE_MAKE_MAPPED:
1221           g_assert (!was_mapped);
1222           clutter_actor_set_mapped (self, TRUE);
1223           break;
1224
1225         case MAP_STATE_MAKE_UNMAPPED:
1226           g_assert (was_mapped);
1227           clutter_actor_set_mapped (self, FALSE);
1228           break;
1229
1230         case MAP_STATE_MAKE_UNREALIZED:
1231           /* we only use MAKE_UNREALIZED in unparent,
1232            * and unparenting a stage isn't possible.
1233            * If someone wants to just unrealize a stage
1234            * then clutter_actor_unrealize() doesn't
1235            * go through this codepath.
1236            */
1237           g_warning ("Trying to force unrealize stage is not allowed");
1238           break;
1239         }
1240
1241       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1242           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1243           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1244         {
1245           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1246                      "it is somehow still mapped",
1247                      _clutter_actor_get_debug_name (self));
1248         }
1249     }
1250   else
1251     {
1252       ClutterActorPrivate *priv = self->priv;
1253       ClutterActor *parent = priv->parent;
1254       gboolean should_be_mapped;
1255       gboolean may_be_realized;
1256       gboolean must_be_realized;
1257
1258       should_be_mapped = FALSE;
1259       may_be_realized = TRUE;
1260       must_be_realized = FALSE;
1261
1262       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1263         {
1264           may_be_realized = FALSE;
1265         }
1266       else
1267         {
1268           /* Maintain invariant that if parent is mapped, and we are
1269            * visible, then we are mapped ...  unless parent is a
1270            * stage, in which case we map regardless of parent's map
1271            * state but do require stage to be visible and realized.
1272            *
1273            * If parent is realized, that does not force us to be
1274            * realized; but if parent is unrealized, that does force
1275            * us to be unrealized.
1276            *
1277            * The reason we don't force children to realize with
1278            * parents is _clutter_actor_rerealize(); if we require that
1279            * a realized parent means children are realized, then to
1280            * unrealize an actor we would have to unrealize its
1281            * parents, which would end up meaning unrealizing and
1282            * hiding the entire stage. So we allow unrealizing a
1283            * child (as long as that child is not mapped) while that
1284            * child still has a realized parent.
1285            *
1286            * Also, if we unrealize from leaf nodes to root, and
1287            * realize from root to leaf, the invariants are never
1288            * violated if we allow children to be unrealized
1289            * while parents are realized.
1290            *
1291            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1292            * to force us to unmap, even though parent is still
1293            * mapped. This is because we're unmapping from leaf nodes
1294            * up to root nodes.
1295            */
1296           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1297               change != MAP_STATE_MAKE_UNMAPPED)
1298             {
1299               gboolean parent_is_visible_realized_toplevel;
1300
1301               parent_is_visible_realized_toplevel =
1302                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1303                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1304                  CLUTTER_ACTOR_IS_REALIZED (parent));
1305
1306               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1307                   parent_is_visible_realized_toplevel)
1308                 {
1309                   must_be_realized = TRUE;
1310                   should_be_mapped = TRUE;
1311                 }
1312             }
1313
1314           /* if the actor has been set to be painted even if unmapped
1315            * then we should map it and check for realization as well;
1316            * this is an override for the branch of the scene graph
1317            * which begins with this node
1318            */
1319           if (priv->enable_paint_unmapped)
1320             {
1321               if (priv->parent == NULL)
1322                 g_warning ("Attempting to map an unparented actor '%s'",
1323                            _clutter_actor_get_debug_name (self));
1324
1325               should_be_mapped = TRUE;
1326               must_be_realized = TRUE;
1327             }
1328
1329           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1330             may_be_realized = FALSE;
1331         }
1332
1333       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1334         {
1335           if (parent == NULL)
1336             g_warning ("Attempting to map a child that does not "
1337                        "meet the necessary invariants: the actor '%s' "
1338                        "has no parent",
1339                        _clutter_actor_get_debug_name (self));
1340           else
1341             g_warning ("Attempting to map a child that does not "
1342                        "meet the necessary invariants: the actor '%s' "
1343                        "is parented to an unmapped actor '%s'",
1344                        _clutter_actor_get_debug_name (self),
1345                        _clutter_actor_get_debug_name (priv->parent));
1346         }
1347
1348       /* If in reparent, we temporarily suspend unmap and unrealize.
1349        *
1350        * We want to go in the order "realize, map" and "unmap, unrealize"
1351        */
1352
1353       /* Unmap */
1354       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1355         clutter_actor_set_mapped (self, FALSE);
1356
1357       /* Realize */
1358       if (must_be_realized)
1359         clutter_actor_realize (self);
1360
1361       /* if we must be realized then we may be, presumably */
1362       g_assert (!(must_be_realized && !may_be_realized));
1363
1364       /* Unrealize */
1365       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1366         clutter_actor_unrealize_not_hiding (self);
1367
1368       /* Map */
1369       if (should_be_mapped)
1370         {
1371           if (!must_be_realized)
1372             g_warning ("Somehow we think actor '%s' should be mapped but "
1373                        "not realized, which isn't allowed",
1374                        _clutter_actor_get_debug_name (self));
1375
1376           /* realization is allowed to fail (though I don't know what
1377            * an app is supposed to do about that - shouldn't it just
1378            * be a g_error? anyway, we have to avoid mapping if this
1379            * happens)
1380            */
1381           if (CLUTTER_ACTOR_IS_REALIZED (self))
1382             clutter_actor_set_mapped (self, TRUE);
1383         }
1384     }
1385
1386 #ifdef CLUTTER_ENABLE_DEBUG
1387   /* check all invariants were kept */
1388   clutter_actor_verify_map_state (self);
1389 #endif
1390 }
1391
1392 static void
1393 clutter_actor_real_map (ClutterActor *self)
1394 {
1395   ClutterActorPrivate *priv = self->priv;
1396   ClutterActor *stage, *iter;
1397
1398   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1399
1400   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1401                 _clutter_actor_get_debug_name (self));
1402
1403   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1404
1405   stage = _clutter_actor_get_stage_internal (self);
1406   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1407
1408   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1409                 priv->pick_id,
1410                 _clutter_actor_get_debug_name (self));
1411
1412   /* notify on parent mapped before potentially mapping
1413    * children, so apps see a top-down notification.
1414    */
1415   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1416
1417   for (iter = self->priv->first_child;
1418        iter != NULL;
1419        iter = iter->priv->next_sibling)
1420     {
1421       clutter_actor_map (iter);
1422     }
1423 }
1424
1425 /**
1426  * clutter_actor_map:
1427  * @self: A #ClutterActor
1428  *
1429  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1430  * and realizes its children if they are visible. Does nothing if the
1431  * actor is not visible.
1432  *
1433  * Calling this function is strongly disencouraged: the default
1434  * implementation of #ClutterActorClass.map() will map all the children
1435  * of an actor when mapping its parent.
1436  *
1437  * When overriding map, it is mandatory to chain up to the parent
1438  * implementation.
1439  *
1440  * Since: 1.0
1441  */
1442 void
1443 clutter_actor_map (ClutterActor *self)
1444 {
1445   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1446
1447   if (CLUTTER_ACTOR_IS_MAPPED (self))
1448     return;
1449
1450   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1451     return;
1452
1453   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1454 }
1455
1456 static void
1457 clutter_actor_real_unmap (ClutterActor *self)
1458 {
1459   ClutterActorPrivate *priv = self->priv;
1460   ClutterActor *iter;
1461
1462   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1463
1464   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1465                 _clutter_actor_get_debug_name (self));
1466
1467   for (iter = self->priv->first_child;
1468        iter != NULL;
1469        iter = iter->priv->next_sibling)
1470     {
1471       clutter_actor_unmap (iter);
1472     }
1473
1474   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1475
1476   /* clear the contents of the last paint volume, so that hiding + moving +
1477    * showing will not result in the wrong area being repainted
1478    */
1479   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1480   priv->last_paint_volume_valid = TRUE;
1481
1482   /* notify on parent mapped after potentially unmapping
1483    * children, so apps see a bottom-up notification.
1484    */
1485   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1486
1487   /* relinquish keyboard focus if we were unmapped while owning it */
1488   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1489     {
1490       ClutterStage *stage;
1491
1492       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1493
1494       if (stage != NULL)
1495         _clutter_stage_release_pick_id (stage, priv->pick_id);
1496
1497       priv->pick_id = -1;
1498
1499       if (stage != NULL &&
1500           clutter_stage_get_key_focus (stage) == self)
1501         {
1502           clutter_stage_set_key_focus (stage, NULL);
1503         }
1504     }
1505 }
1506
1507 /**
1508  * clutter_actor_unmap:
1509  * @self: A #ClutterActor
1510  *
1511  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1512  * unmaps its children if they were mapped.
1513  *
1514  * Calling this function is not encouraged: the default #ClutterActor
1515  * implementation of #ClutterActorClass.unmap() will also unmap any
1516  * eventual children by default when their parent is unmapped.
1517  *
1518  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1519  * chain up to the parent implementation.
1520  *
1521  * <note>It is important to note that the implementation of the
1522  * #ClutterActorClass.unmap() virtual function may be called after
1523  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1524  * implementation, but it is guaranteed to be called before the
1525  * #GObjectClass.finalize() implementation.</note>
1526  *
1527  * Since: 1.0
1528  */
1529 void
1530 clutter_actor_unmap (ClutterActor *self)
1531 {
1532   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1533
1534   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1535     return;
1536
1537   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1538 }
1539
1540 static void
1541 clutter_actor_real_show (ClutterActor *self)
1542 {
1543   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1544     {
1545       ClutterActorPrivate *priv = self->priv;
1546
1547       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1548
1549       /* we notify on the "visible" flag in the clutter_actor_show()
1550        * wrapper so the entire show signal emission completes first
1551        * (?)
1552        */
1553       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1554
1555       /* we queue a relayout unless the actor is inside a
1556        * container that explicitly told us not to
1557        */
1558       if (priv->parent != NULL &&
1559           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1560         {
1561           /* While an actor is hidden the parent may not have
1562            * allocated/requested so we need to start from scratch
1563            * and avoid the short-circuiting in
1564            * clutter_actor_queue_relayout().
1565            */
1566           priv->needs_width_request  = FALSE;
1567           priv->needs_height_request = FALSE;
1568           priv->needs_allocation     = FALSE;
1569           clutter_actor_queue_relayout (self);
1570         }
1571     }
1572 }
1573
1574 static inline void
1575 set_show_on_set_parent (ClutterActor *self,
1576                         gboolean      set_show)
1577 {
1578   ClutterActorPrivate *priv = self->priv;
1579
1580   set_show = !!set_show;
1581
1582   if (priv->show_on_set_parent == set_show)
1583     return;
1584
1585   if (priv->parent == NULL)
1586     {
1587       priv->show_on_set_parent = set_show;
1588       g_object_notify_by_pspec (G_OBJECT (self),
1589                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1590     }
1591 }
1592
1593 /**
1594  * clutter_actor_show:
1595  * @self: A #ClutterActor
1596  *
1597  * Flags an actor to be displayed. An actor that isn't shown will not
1598  * be rendered on the stage.
1599  *
1600  * Actors are visible by default.
1601  *
1602  * If this function is called on an actor without a parent, the
1603  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1604  * effect.
1605  */
1606 void
1607 clutter_actor_show (ClutterActor *self)
1608 {
1609   ClutterActorPrivate *priv;
1610
1611   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1612
1613   /* simple optimization */
1614   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1615     {
1616       /* we still need to set the :show-on-set-parent property, in
1617        * case show() is called on an unparented actor
1618        */
1619       set_show_on_set_parent (self, TRUE);
1620       return;
1621     }
1622
1623 #ifdef CLUTTER_ENABLE_DEBUG
1624   clutter_actor_verify_map_state (self);
1625 #endif
1626
1627   priv = self->priv;
1628
1629   g_object_freeze_notify (G_OBJECT (self));
1630
1631   set_show_on_set_parent (self, TRUE);
1632
1633   /* if we're showing a child that needs to expand, or may
1634    * expand, then we need to recompute the expand flags for
1635    * its parent as well
1636    */
1637   if (priv->needs_compute_expand ||
1638       priv->needs_x_expand ||
1639       priv->needs_y_expand)
1640     {
1641       clutter_actor_queue_compute_expand (self);
1642     }
1643
1644   g_signal_emit (self, actor_signals[SHOW], 0);
1645   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1646
1647   if (priv->parent != NULL)
1648     clutter_actor_queue_redraw (priv->parent);
1649
1650   g_object_thaw_notify (G_OBJECT (self));
1651 }
1652
1653 /**
1654  * clutter_actor_show_all:
1655  * @self: a #ClutterActor
1656  *
1657  * Calls clutter_actor_show() on all children of an actor (if any).
1658  *
1659  * Since: 0.2
1660  *
1661  * Deprecated: 1.10: Actors are visible by default
1662  */
1663 void
1664 clutter_actor_show_all (ClutterActor *self)
1665 {
1666   ClutterActorClass *klass;
1667
1668   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1669
1670   klass = CLUTTER_ACTOR_GET_CLASS (self);
1671   if (klass->show_all)
1672     klass->show_all (self);
1673 }
1674
1675 static void
1676 clutter_actor_real_hide (ClutterActor *self)
1677 {
1678   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1679     {
1680       ClutterActorPrivate *priv = self->priv;
1681
1682       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1683
1684       /* we notify on the "visible" flag in the clutter_actor_hide()
1685        * wrapper so the entire hide signal emission completes first
1686        * (?)
1687        */
1688       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1689
1690       /* we queue a relayout unless the actor is inside a
1691        * container that explicitly told us not to
1692        */
1693       if (priv->parent != NULL &&
1694           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1695         clutter_actor_queue_relayout (priv->parent);
1696     }
1697 }
1698
1699 /**
1700  * clutter_actor_hide:
1701  * @self: A #ClutterActor
1702  *
1703  * Flags an actor to be hidden. A hidden actor will not be
1704  * rendered on the stage.
1705  *
1706  * Actors are visible by default.
1707  *
1708  * If this function is called on an actor without a parent, the
1709  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1710  * as a side-effect.
1711  */
1712 void
1713 clutter_actor_hide (ClutterActor *self)
1714 {
1715   ClutterActorPrivate *priv;
1716
1717   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1718
1719   /* simple optimization */
1720   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1721     {
1722       /* we still need to set the :show-on-set-parent property, in
1723        * case hide() is called on an unparented actor
1724        */
1725       set_show_on_set_parent (self, FALSE);
1726       return;
1727     }
1728
1729 #ifdef CLUTTER_ENABLE_DEBUG
1730   clutter_actor_verify_map_state (self);
1731 #endif
1732
1733   priv = self->priv;
1734
1735   g_object_freeze_notify (G_OBJECT (self));
1736
1737   set_show_on_set_parent (self, FALSE);
1738
1739   /* if we're hiding a child that needs to expand, or may
1740    * expand, then we need to recompute the expand flags for
1741    * its parent as well
1742    */
1743   if (priv->needs_compute_expand ||
1744       priv->needs_x_expand ||
1745       priv->needs_y_expand)
1746     {
1747       clutter_actor_queue_compute_expand (self);
1748     }
1749
1750   g_signal_emit (self, actor_signals[HIDE], 0);
1751   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1752
1753   if (priv->parent != NULL)
1754     clutter_actor_queue_redraw (priv->parent);
1755
1756   g_object_thaw_notify (G_OBJECT (self));
1757 }
1758
1759 /**
1760  * clutter_actor_hide_all:
1761  * @self: a #ClutterActor
1762  *
1763  * Calls clutter_actor_hide() on all child actors (if any).
1764  *
1765  * Since: 0.2
1766  *
1767  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1768  *   prevent its children from being painted as well.
1769  */
1770 void
1771 clutter_actor_hide_all (ClutterActor *self)
1772 {
1773   ClutterActorClass *klass;
1774
1775   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1776
1777   klass = CLUTTER_ACTOR_GET_CLASS (self);
1778   if (klass->hide_all)
1779     klass->hide_all (self);
1780 }
1781
1782 /**
1783  * clutter_actor_realize:
1784  * @self: A #ClutterActor
1785  *
1786  * Realization informs the actor that it is attached to a stage. It
1787  * can use this to allocate resources if it wanted to delay allocation
1788  * until it would be rendered. However it is perfectly acceptable for
1789  * an actor to create resources before being realized because Clutter
1790  * only ever has a single rendering context so that actor is free to
1791  * be moved from one stage to another.
1792  *
1793  * This function does nothing if the actor is already realized.
1794  *
1795  * Because a realized actor must have realized parent actors, calling
1796  * clutter_actor_realize() will also realize all parents of the actor.
1797  *
1798  * This function does not realize child actors, except in the special
1799  * case that realizing the stage, when the stage is visible, will
1800  * suddenly map (and thus realize) the children of the stage.
1801  **/
1802 void
1803 clutter_actor_realize (ClutterActor *self)
1804 {
1805   ClutterActorPrivate *priv;
1806
1807   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1808
1809   priv = self->priv;
1810
1811 #ifdef CLUTTER_ENABLE_DEBUG
1812   clutter_actor_verify_map_state (self);
1813 #endif
1814
1815   if (CLUTTER_ACTOR_IS_REALIZED (self))
1816     return;
1817
1818   /* To be realized, our parent actors must be realized first.
1819    * This will only succeed if we're inside a toplevel.
1820    */
1821   if (priv->parent != NULL)
1822     clutter_actor_realize (priv->parent);
1823
1824   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1825     {
1826       /* toplevels can be realized at any time */
1827     }
1828   else
1829     {
1830       /* "Fail" the realization if parent is missing or unrealized;
1831        * this should really be a g_warning() not some kind of runtime
1832        * failure; how can an app possibly recover? Instead it's a bug
1833        * in the app and the app should get an explanatory warning so
1834        * someone can fix it. But for now it's too hard to fix this
1835        * because e.g. ClutterTexture needs reworking.
1836        */
1837       if (priv->parent == NULL ||
1838           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1839         return;
1840     }
1841
1842   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1843
1844   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1845   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1846
1847   g_signal_emit (self, actor_signals[REALIZE], 0);
1848
1849   /* Stage actor is allowed to unset the realized flag again in its
1850    * default signal handler, though that is a pathological situation.
1851    */
1852
1853   /* If realization "failed" we'll have to update child state. */
1854   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1855 }
1856
1857 static void
1858 clutter_actor_real_unrealize (ClutterActor *self)
1859 {
1860   /* we must be unmapped (implying our children are also unmapped) */
1861   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1862 }
1863
1864 /**
1865  * clutter_actor_unrealize:
1866  * @self: A #ClutterActor
1867  *
1868  * Unrealization informs the actor that it may be being destroyed or
1869  * moved to another stage. The actor may want to destroy any
1870  * underlying graphics resources at this point. However it is
1871  * perfectly acceptable for it to retain the resources until the actor
1872  * is destroyed because Clutter only ever uses a single rendering
1873  * context and all of the graphics resources are valid on any stage.
1874  *
1875  * Because mapped actors must be realized, actors may not be
1876  * unrealized if they are mapped. This function hides the actor to be
1877  * sure it isn't mapped, an application-visible side effect that you
1878  * may not be expecting.
1879  *
1880  * This function should not be called by application code.
1881  */
1882 void
1883 clutter_actor_unrealize (ClutterActor *self)
1884 {
1885   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1886   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1887
1888 /* This function should not really be in the public API, because
1889  * there isn't a good reason to call it. ClutterActor will already
1890  * unrealize things for you when it's important to do so.
1891  *
1892  * If you were using clutter_actor_unrealize() in a dispose
1893  * implementation, then don't, just chain up to ClutterActor's
1894  * dispose.
1895  *
1896  * If you were using clutter_actor_unrealize() to implement
1897  * unrealizing children of your container, then don't, ClutterActor
1898  * will already take care of that.
1899  *
1900  * If you were using clutter_actor_unrealize() to re-realize to
1901  * create your resources in a different way, then use
1902  * _clutter_actor_rerealize() (inside Clutter) or just call your
1903  * code that recreates your resources directly (outside Clutter).
1904  */
1905
1906 #ifdef CLUTTER_ENABLE_DEBUG
1907   clutter_actor_verify_map_state (self);
1908 #endif
1909
1910   clutter_actor_hide (self);
1911
1912   clutter_actor_unrealize_not_hiding (self);
1913 }
1914
1915 static ClutterActorTraverseVisitFlags
1916 unrealize_actor_before_children_cb (ClutterActor *self,
1917                                     int depth,
1918                                     void *user_data)
1919 {
1920   /* If an actor is already unrealized we know its children have also
1921    * already been unrealized... */
1922   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1923     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1924
1925   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1926
1927   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1928 }
1929
1930 static ClutterActorTraverseVisitFlags
1931 unrealize_actor_after_children_cb (ClutterActor *self,
1932                                    int depth,
1933                                    void *user_data)
1934 {
1935   /* We want to unset the realized flag only _after_
1936    * child actors are unrealized, to maintain invariants.
1937    */
1938   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1939   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1940   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1941 }
1942
1943 /*
1944  * clutter_actor_unrealize_not_hiding:
1945  * @self: A #ClutterActor
1946  *
1947  * Unrealization informs the actor that it may be being destroyed or
1948  * moved to another stage. The actor may want to destroy any
1949  * underlying graphics resources at this point. However it is
1950  * perfectly acceptable for it to retain the resources until the actor
1951  * is destroyed because Clutter only ever uses a single rendering
1952  * context and all of the graphics resources are valid on any stage.
1953  *
1954  * Because mapped actors must be realized, actors may not be
1955  * unrealized if they are mapped. You must hide the actor or one of
1956  * its parents before attempting to unrealize.
1957  *
1958  * This function is separate from clutter_actor_unrealize() because it
1959  * does not automatically hide the actor.
1960  * Actors need not be hidden to be unrealized, they just need to
1961  * be unmapped. In fact we don't want to mess up the application's
1962  * setting of the "visible" flag, so hiding is very undesirable.
1963  *
1964  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1965  * backward compatibility.
1966  */
1967 static void
1968 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1969 {
1970   _clutter_actor_traverse (self,
1971                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1972                            unrealize_actor_before_children_cb,
1973                            unrealize_actor_after_children_cb,
1974                            NULL);
1975 }
1976
1977 /*
1978  * _clutter_actor_rerealize:
1979  * @self: A #ClutterActor
1980  * @callback: Function to call while unrealized
1981  * @data: data for callback
1982  *
1983  * If an actor is already unrealized, this just calls the callback.
1984  *
1985  * If it is realized, it unrealizes temporarily, calls the callback,
1986  * and then re-realizes the actor.
1987  *
1988  * As a side effect, leaves all children of the actor unrealized if
1989  * the actor was realized but not showing.  This is because when we
1990  * unrealize the actor temporarily we must unrealize its children
1991  * (e.g. children of a stage can't be realized if stage window is
1992  * gone). And we aren't clever enough to save the realization state of
1993  * all children. In most cases this should not matter, because
1994  * the children will automatically realize when they next become mapped.
1995  */
1996 void
1997 _clutter_actor_rerealize (ClutterActor    *self,
1998                           ClutterCallback  callback,
1999                           void            *data)
2000 {
2001   gboolean was_mapped;
2002   gboolean was_showing;
2003   gboolean was_realized;
2004
2005   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2006
2007 #ifdef CLUTTER_ENABLE_DEBUG
2008   clutter_actor_verify_map_state (self);
2009 #endif
2010
2011   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
2012   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
2013   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
2014
2015   /* Must be unmapped to unrealize. Note we only have to hide this
2016    * actor if it was mapped (if all parents were showing).  If actor
2017    * is merely visible (but not mapped), then that's fine, we can
2018    * leave it visible.
2019    */
2020   if (was_mapped)
2021     clutter_actor_hide (self);
2022
2023   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
2024
2025   /* unrealize self and all children */
2026   clutter_actor_unrealize_not_hiding (self);
2027
2028   if (callback != NULL)
2029     {
2030       (* callback) (self, data);
2031     }
2032
2033   if (was_showing)
2034     clutter_actor_show (self); /* will realize only if mapping implies it */
2035   else if (was_realized)
2036     clutter_actor_realize (self); /* realize self and all parents */
2037 }
2038
2039 static void
2040 clutter_actor_real_pick (ClutterActor       *self,
2041                          const ClutterColor *color)
2042 {
2043   /* the default implementation is just to paint a rectangle
2044    * with the same size of the actor using the passed color
2045    */
2046   if (clutter_actor_should_pick_paint (self))
2047     {
2048       ClutterActorBox box = { 0, };
2049       float width, height;
2050
2051       clutter_actor_get_allocation_box (self, &box);
2052
2053       width = box.x2 - box.x1;
2054       height = box.y2 - box.y1;
2055
2056       cogl_set_source_color4ub (color->red,
2057                                 color->green,
2058                                 color->blue,
2059                                 color->alpha);
2060
2061       cogl_rectangle (0, 0, width, height);
2062     }
2063
2064   /* XXX - this thoroughly sucks, but we need to maintain compatibility
2065    * with existing container classes that override the pick() virtual
2066    * and chain up to the default implementation - otherwise we'll end up
2067    * painting our children twice.
2068    *
2069    * this has to go away for 2.0; hopefully along the pick() itself.
2070    */
2071   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2072     {
2073       ClutterActor *iter;
2074
2075       for (iter = self->priv->first_child;
2076            iter != NULL;
2077            iter = iter->priv->next_sibling)
2078         clutter_actor_paint (iter);
2079     }
2080 }
2081
2082 /**
2083  * clutter_actor_should_pick_paint:
2084  * @self: A #ClutterActor
2085  *
2086  * Should be called inside the implementation of the
2087  * #ClutterActor::pick virtual function in order to check whether
2088  * the actor should paint itself in pick mode or not.
2089  *
2090  * This function should never be called directly by applications.
2091  *
2092  * Return value: %TRUE if the actor should paint its silhouette,
2093  *   %FALSE otherwise
2094  */
2095 gboolean
2096 clutter_actor_should_pick_paint (ClutterActor *self)
2097 {
2098   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2099
2100   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2101       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2102        CLUTTER_ACTOR_IS_REACTIVE (self)))
2103     return TRUE;
2104
2105   return FALSE;
2106 }
2107
2108 static void
2109 clutter_actor_real_get_preferred_width (ClutterActor *self,
2110                                         gfloat        for_height,
2111                                         gfloat       *min_width_p,
2112                                         gfloat       *natural_width_p)
2113 {
2114   ClutterActorPrivate *priv = self->priv;
2115
2116   if (priv->n_children != 0 &&
2117       priv->layout_manager != NULL)
2118     {
2119       ClutterContainer *container = CLUTTER_CONTAINER (self);
2120
2121       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2122                     "for the preferred width",
2123                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2124                     priv->layout_manager);
2125
2126       clutter_layout_manager_get_preferred_width (priv->layout_manager,
2127                                                   container,
2128                                                   for_height,
2129                                                   min_width_p,
2130                                                   natural_width_p);
2131
2132       return;
2133     }
2134
2135   /* Default implementation is always 0x0, usually an actor
2136    * using this default is relying on someone to set the
2137    * request manually
2138    */
2139   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2140
2141   if (min_width_p)
2142     *min_width_p = 0;
2143
2144   if (natural_width_p)
2145     *natural_width_p = 0;
2146 }
2147
2148 static void
2149 clutter_actor_real_get_preferred_height (ClutterActor *self,
2150                                          gfloat        for_width,
2151                                          gfloat       *min_height_p,
2152                                          gfloat       *natural_height_p)
2153 {
2154   ClutterActorPrivate *priv = self->priv;
2155
2156   if (priv->n_children != 0 &&
2157       priv->layout_manager != NULL)
2158     {
2159       ClutterContainer *container = CLUTTER_CONTAINER (self);
2160
2161       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2162                     "for the preferred height",
2163                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2164                     priv->layout_manager);
2165
2166       clutter_layout_manager_get_preferred_height (priv->layout_manager,
2167                                                    container,
2168                                                    for_width,
2169                                                    min_height_p,
2170                                                    natural_height_p);
2171
2172       return;
2173     }
2174   /* Default implementation is always 0x0, usually an actor
2175    * using this default is relying on someone to set the
2176    * request manually
2177    */
2178   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2179
2180   if (min_height_p)
2181     *min_height_p = 0;
2182
2183   if (natural_height_p)
2184     *natural_height_p = 0;
2185 }
2186
2187 static void
2188 clutter_actor_store_old_geometry (ClutterActor    *self,
2189                                   ClutterActorBox *box)
2190 {
2191   *box = self->priv->allocation;
2192 }
2193
2194 static inline void
2195 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2196                                           const ClutterActorBox *old)
2197 {
2198   ClutterActorPrivate *priv = self->priv;
2199   GObject *obj = G_OBJECT (self);
2200
2201   g_object_freeze_notify (obj);
2202
2203   /* to avoid excessive requisition or allocation cycles we
2204    * use the cached values.
2205    *
2206    * - if we don't have an allocation we assume that we need
2207    *   to notify anyway
2208    * - if we don't have a width or a height request we notify
2209    *   width and height
2210    * - if we have a valid allocation then we check the old
2211    *   bounding box with the current allocation and we notify
2212    *   the changes
2213    */
2214   if (priv->needs_allocation)
2215     {
2216       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2217       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2218       g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2219       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2220       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2221       g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2222     }
2223   else if (priv->needs_width_request || priv->needs_height_request)
2224     {
2225       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2226       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2227       g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2228     }
2229   else
2230     {
2231       gfloat x, y;
2232       gfloat width, height;
2233
2234       x = priv->allocation.x1;
2235       y = priv->allocation.y1;
2236       width = priv->allocation.x2 - priv->allocation.x1;
2237       height = priv->allocation.y2 - priv->allocation.y1;
2238
2239       if (x != old->x1)
2240         {
2241           g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2242           g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2243         }
2244
2245       if (y != old->y1)
2246         {
2247           g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2248           g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2249         }
2250
2251       if (width != (old->x2 - old->x1))
2252         {
2253           g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2254           g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2255         }
2256
2257       if (height != (old->y2 - old->y1))
2258         {
2259           g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2260           g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2261         }
2262     }
2263
2264   g_object_thaw_notify (obj);
2265 }
2266
2267 /*< private >
2268  * clutter_actor_set_allocation_internal:
2269  * @self: a #ClutterActor
2270  * @box: a #ClutterActorBox
2271  * @flags: allocation flags
2272  *
2273  * Stores the allocation of @self.
2274  *
2275  * This function only performs basic storage and property notification.
2276  *
2277  * This function should be called by clutter_actor_set_allocation()
2278  * and by the default implementation of #ClutterActorClass.allocate().
2279  *
2280  * Return value: %TRUE if the allocation of the #ClutterActor has been
2281  *   changed, and %FALSE otherwise
2282  */
2283 static inline gboolean
2284 clutter_actor_set_allocation_internal (ClutterActor           *self,
2285                                        const ClutterActorBox  *box,
2286                                        ClutterAllocationFlags  flags)
2287 {
2288   ClutterActorPrivate *priv = self->priv;
2289   GObject *obj;
2290   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2291   gboolean retval;
2292   ClutterActorBox old_alloc = { 0, };
2293
2294   obj = G_OBJECT (self);
2295
2296   g_object_freeze_notify (obj);
2297
2298   clutter_actor_store_old_geometry (self, &old_alloc);
2299
2300   x1_changed = priv->allocation.x1 != box->x1;
2301   y1_changed = priv->allocation.y1 != box->y1;
2302   x2_changed = priv->allocation.x2 != box->x2;
2303   y2_changed = priv->allocation.y2 != box->y2;
2304
2305   priv->allocation = *box;
2306   priv->allocation_flags = flags;
2307
2308   /* allocation is authoritative */
2309   priv->needs_width_request = FALSE;
2310   priv->needs_height_request = FALSE;
2311   priv->needs_allocation = FALSE;
2312
2313   if (x1_changed ||
2314       y1_changed ||
2315       x2_changed ||
2316       y2_changed)
2317     {
2318       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2319                     _clutter_actor_get_debug_name (self));
2320
2321       priv->transform_valid = FALSE;
2322
2323       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2324
2325       /* if the allocation changes, so does the content box */
2326       if (priv->content != NULL)
2327         {
2328           priv->content_box_valid = FALSE;
2329           g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2330         }
2331
2332       retval = TRUE;
2333     }
2334   else
2335     retval = FALSE;
2336
2337   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2338
2339   g_object_thaw_notify (obj);
2340
2341   return retval;
2342 }
2343
2344 static void clutter_actor_real_allocate (ClutterActor           *self,
2345                                          const ClutterActorBox  *box,
2346                                          ClutterAllocationFlags  flags);
2347
2348 static inline void
2349 clutter_actor_maybe_layout_children (ClutterActor           *self,
2350                                      const ClutterActorBox  *allocation,
2351                                      ClutterAllocationFlags  flags)
2352 {
2353   ClutterActorPrivate *priv = self->priv;
2354
2355   /* this is going to be a bit hard to follow, so let's put an explanation
2356    * here.
2357    *
2358    * we want ClutterActor to have a default layout manager if the actor was
2359    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2360    *
2361    * we also want any subclass of ClutterActor that does not override the
2362    * ::allocate() virtual function to delegate to a layout manager.
2363    *
2364    * finally, we want to allow people subclassing ClutterActor and overriding
2365    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2366    *
2367    * on the other hand, we want existing actor subclasses overriding the
2368    * ::allocate() virtual function and chaining up to the parent's
2369    * implementation to continue working without allocating their children
2370    * twice, or without entering an allocation loop.
2371    *
2372    * for the first two points, we check if the class of the actor is
2373    * overridding the ::allocate() virtual function; if it isn't, then we
2374    * follow through with checking whether we have children and a layout
2375    * manager, and eventually calling clutter_layout_manager_allocate().
2376    *
2377    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2378    * allocation flags that we got passed, and if it is present, we continue
2379    * with the check above.
2380    *
2381    * if neither of these two checks yields a positive result, we just
2382    * assume that the ::allocate() virtual function that resulted in this
2383    * function being called will also allocate the children of the actor.
2384    */
2385
2386   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2387     goto check_layout;
2388
2389   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2390     goto check_layout;
2391
2392   return;
2393
2394 check_layout:
2395   if (priv->n_children != 0 &&
2396       priv->layout_manager != NULL)
2397     {
2398       ClutterContainer *container = CLUTTER_CONTAINER (self);
2399       ClutterAllocationFlags children_flags;
2400       ClutterActorBox children_box;
2401
2402       /* normalize the box passed to the layout manager */
2403       children_box.x1 = children_box.y1 = 0.f;
2404       children_box.x2 = (allocation->x2 - allocation->x1);
2405       children_box.y2 = (allocation->y2 - allocation->y1);
2406
2407       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2408        * the actor's children, since it refers only to the current
2409        * actor's allocation.
2410        */
2411       children_flags = flags;
2412       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2413
2414       CLUTTER_NOTE (LAYOUT,
2415                     "Allocating %d children of %s "
2416                     "at { %.2f, %.2f - %.2f x %.2f } "
2417                     "using %s",
2418                     priv->n_children,
2419                     _clutter_actor_get_debug_name (self),
2420                     allocation->x1,
2421                     allocation->y1,
2422                     (allocation->x2 - allocation->x1),
2423                     (allocation->y2 - allocation->y1),
2424                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2425
2426       clutter_layout_manager_allocate (priv->layout_manager,
2427                                        container,
2428                                        &children_box,
2429                                        children_flags);
2430     }
2431 }
2432
2433 static void
2434 clutter_actor_real_allocate (ClutterActor           *self,
2435                              const ClutterActorBox  *box,
2436                              ClutterAllocationFlags  flags)
2437 {
2438   ClutterActorPrivate *priv = self->priv;
2439   gboolean changed;
2440
2441   g_object_freeze_notify (G_OBJECT (self));
2442
2443   changed = clutter_actor_set_allocation_internal (self, box, flags);
2444
2445   /* we allocate our children before we notify changes in our geometry,
2446    * so that people connecting to properties will be able to get valid
2447    * data out of the sub-tree of the scene graph that has this actor at
2448    * the root.
2449    */
2450   clutter_actor_maybe_layout_children (self, box, flags);
2451
2452   if (changed)
2453     {
2454       ClutterActorBox signal_box = priv->allocation;
2455       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2456
2457       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2458                      &signal_box,
2459                      signal_flags);
2460     }
2461
2462   g_object_thaw_notify (G_OBJECT (self));
2463 }
2464
2465 static void
2466 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2467                                     ClutterActor *origin)
2468 {
2469   /* no point in queuing a redraw on a destroyed actor */
2470   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2471     return;
2472
2473   /* NB: We can't bail out early here if the actor is hidden in case
2474    * the actor bas been cloned. In this case the clone will need to
2475    * receive the signal so it can queue its own redraw.
2476    */
2477
2478   /* calls klass->queue_redraw in default handler */
2479   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2480 }
2481
2482 static void
2483 clutter_actor_real_queue_redraw (ClutterActor *self,
2484                                  ClutterActor *origin)
2485 {
2486   ClutterActor *parent;
2487
2488   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2489                 _clutter_actor_get_debug_name (self),
2490                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2491                                : "same actor");
2492
2493   /* no point in queuing a redraw on a destroyed actor */
2494   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2495     return;
2496
2497   /* If the queue redraw is coming from a child then the actor has
2498      become dirty and any queued effect is no longer valid */
2499   if (self != origin)
2500     {
2501       self->priv->is_dirty = TRUE;
2502       self->priv->effect_to_redraw = NULL;
2503     }
2504
2505   /* If the actor isn't visible, we still had to emit the signal
2506    * to allow for a ClutterClone, but the appearance of the parent
2507    * won't change so we don't have to propagate up the hierarchy.
2508    */
2509   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2510     return;
2511
2512   /* Although we could determine here that a full stage redraw
2513    * has already been queued and immediately bail out, we actually
2514    * guarantee that we will propagate a queue-redraw signal to our
2515    * parent at least once so that it's possible to implement a
2516    * container that tracks which of its children have queued a
2517    * redraw.
2518    */
2519   if (self->priv->propagated_one_redraw)
2520     {
2521       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2522       if (stage != NULL &&
2523           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2524         return;
2525     }
2526
2527   self->priv->propagated_one_redraw = TRUE;
2528
2529   /* notify parents, if they are all visible eventually we'll
2530    * queue redraw on the stage, which queues the redraw idle.
2531    */
2532   parent = clutter_actor_get_parent (self);
2533   if (parent != NULL)
2534     {
2535       /* this will go up recursively */
2536       _clutter_actor_signal_queue_redraw (parent, origin);
2537     }
2538 }
2539
2540 static void
2541 clutter_actor_real_queue_relayout (ClutterActor *self)
2542 {
2543   ClutterActorPrivate *priv = self->priv;
2544
2545   /* no point in queueing a redraw on a destroyed actor */
2546   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2547     return;
2548
2549   priv->needs_width_request  = TRUE;
2550   priv->needs_height_request = TRUE;
2551   priv->needs_allocation     = TRUE;
2552
2553   /* reset the cached size requests */
2554   memset (priv->width_requests, 0,
2555           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2556   memset (priv->height_requests, 0,
2557           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2558
2559   /* We need to go all the way up the hierarchy */
2560   if (priv->parent != NULL)
2561     _clutter_actor_queue_only_relayout (priv->parent);
2562 }
2563
2564 /**
2565  * clutter_actor_apply_relative_transform_to_point:
2566  * @self: A #ClutterActor
2567  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2568  *   default #ClutterStage
2569  * @point: A point as #ClutterVertex
2570  * @vertex: (out caller-allocates): The translated #ClutterVertex
2571  *
2572  * Transforms @point in coordinates relative to the actor into
2573  * ancestor-relative coordinates using the relevant transform
2574  * stack (i.e. scale, rotation, etc).
2575  *
2576  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2577  * this case, the coordinates returned will be the coordinates on
2578  * the stage before the projection is applied. This is different from
2579  * the behaviour of clutter_actor_apply_transform_to_point().
2580  *
2581  * Since: 0.6
2582  */
2583 void
2584 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2585                                                  ClutterActor        *ancestor,
2586                                                  const ClutterVertex *point,
2587                                                  ClutterVertex       *vertex)
2588 {
2589   gfloat w;
2590   CoglMatrix matrix;
2591
2592   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2593   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2594   g_return_if_fail (point != NULL);
2595   g_return_if_fail (vertex != NULL);
2596
2597   *vertex = *point;
2598   w = 1.0;
2599
2600   if (ancestor == NULL)
2601     ancestor = _clutter_actor_get_stage_internal (self);
2602
2603   if (ancestor == NULL)
2604     {
2605       *vertex = *point;
2606       return;
2607     }
2608
2609   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2610   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2611 }
2612
2613 static gboolean
2614 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2615                                          const ClutterVertex *vertices_in,
2616                                          ClutterVertex *vertices_out,
2617                                          int n_vertices)
2618 {
2619   ClutterActor *stage;
2620   CoglMatrix modelview;
2621   CoglMatrix projection;
2622   float viewport[4];
2623
2624   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2625
2626   stage = _clutter_actor_get_stage_internal (self);
2627
2628   /* We really can't do anything meaningful in this case so don't try
2629    * to do any transform */
2630   if (stage == NULL)
2631     return FALSE;
2632
2633   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2634    * that gets us to stage coordinates, we want to go all the way to eye
2635    * coordinates */
2636   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2637
2638   /* Fetch the projection and viewport */
2639   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2640   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2641                                &viewport[0],
2642                                &viewport[1],
2643                                &viewport[2],
2644                                &viewport[3]);
2645
2646   _clutter_util_fully_transform_vertices (&modelview,
2647                                           &projection,
2648                                           viewport,
2649                                           vertices_in,
2650                                           vertices_out,
2651                                           n_vertices);
2652
2653   return TRUE;
2654 }
2655
2656 /**
2657  * clutter_actor_apply_transform_to_point:
2658  * @self: A #ClutterActor
2659  * @point: A point as #ClutterVertex
2660  * @vertex: (out caller-allocates): The translated #ClutterVertex
2661  *
2662  * Transforms @point in coordinates relative to the actor
2663  * into screen-relative coordinates with the current actor
2664  * transformation (i.e. scale, rotation, etc)
2665  *
2666  * Since: 0.4
2667  **/
2668 void
2669 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2670                                         const ClutterVertex *point,
2671                                         ClutterVertex       *vertex)
2672 {
2673   g_return_if_fail (point != NULL);
2674   g_return_if_fail (vertex != NULL);
2675   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2676 }
2677
2678 /*
2679  * _clutter_actor_get_relative_transformation_matrix:
2680  * @self: The actor whose coordinate space you want to transform from.
2681  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2682  *            or %NULL if you want to transform all the way to eye coordinates.
2683  * @matrix: A #CoglMatrix to store the transformation
2684  *
2685  * This gets a transformation @matrix that will transform coordinates from the
2686  * coordinate space of @self into the coordinate space of @ancestor.
2687  *
2688  * For example if you need a matrix that can transform the local actor
2689  * coordinates of @self into stage coordinates you would pass the actor's stage
2690  * pointer as the @ancestor.
2691  *
2692  * If you pass %NULL then the transformation will take you all the way through
2693  * to eye coordinates. This can be useful if you want to extract the entire
2694  * modelview transform that Clutter applies before applying the projection
2695  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2696  * using cogl_set_modelview_matrix() for example then you would want a matrix
2697  * that transforms into eye coordinates.
2698  *
2699  * <note><para>This function explicitly initializes the given @matrix. If you just
2700  * want clutter to multiply a relative transformation with an existing matrix
2701  * you can use clutter_actor_apply_relative_transformation_matrix()
2702  * instead.</para></note>
2703  *
2704  */
2705 /* XXX: We should consider caching the stage relative modelview along with
2706  * the actor itself */
2707 static void
2708 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2709                                                    ClutterActor *ancestor,
2710                                                    CoglMatrix *matrix)
2711 {
2712   cogl_matrix_init_identity (matrix);
2713
2714   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2715 }
2716
2717 /* Project the given @box into stage window coordinates, writing the
2718  * transformed vertices to @verts[]. */
2719 static gboolean
2720 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2721                                           const ClutterActorBox *box,
2722                                           ClutterVertex          verts[])
2723 {
2724   ClutterVertex box_vertices[4];
2725
2726   box_vertices[0].x = box->x1;
2727   box_vertices[0].y = box->y1;
2728   box_vertices[0].z = 0;
2729   box_vertices[1].x = box->x2;
2730   box_vertices[1].y = box->y1;
2731   box_vertices[1].z = 0;
2732   box_vertices[2].x = box->x1;
2733   box_vertices[2].y = box->y2;
2734   box_vertices[2].z = 0;
2735   box_vertices[3].x = box->x2;
2736   box_vertices[3].y = box->y2;
2737   box_vertices[3].z = 0;
2738
2739   return
2740     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2741 }
2742
2743 /**
2744  * clutter_actor_get_allocation_vertices:
2745  * @self: A #ClutterActor
2746  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2747  *   against, or %NULL to use the #ClutterStage
2748  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2749  *   location for an array of 4 #ClutterVertex in which to store the result
2750  *
2751  * Calculates the transformed coordinates of the four corners of the
2752  * actor in the plane of @ancestor. The returned vertices relate to
2753  * the #ClutterActorBox coordinates as follows:
2754  * <itemizedlist>
2755  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2756  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2757  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2758  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2759  * </itemizedlist>
2760  *
2761  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2762  * this case, the coordinates returned will be the coordinates on
2763  * the stage before the projection is applied. This is different from
2764  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2765  *
2766  * Since: 0.6
2767  */
2768 void
2769 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2770                                        ClutterActor  *ancestor,
2771                                        ClutterVertex  verts[])
2772 {
2773   ClutterActorPrivate *priv;
2774   ClutterActorBox box;
2775   ClutterVertex vertices[4];
2776   CoglMatrix modelview;
2777
2778   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2779   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2780
2781   if (ancestor == NULL)
2782     ancestor = _clutter_actor_get_stage_internal (self);
2783
2784   /* Fallback to a NOP transform if the actor isn't parented under a
2785    * stage. */
2786   if (ancestor == NULL)
2787     ancestor = self;
2788
2789   priv = self->priv;
2790
2791   /* if the actor needs to be allocated we force a relayout, so that
2792    * we will have valid values to use in the transformations */
2793   if (priv->needs_allocation)
2794     {
2795       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2796       if (stage)
2797         _clutter_stage_maybe_relayout (stage);
2798       else
2799         {
2800           box.x1 = box.y1 = 0;
2801           /* The result isn't really meaningful in this case but at
2802            * least try to do something *vaguely* reasonable... */
2803           clutter_actor_get_size (self, &box.x2, &box.y2);
2804         }
2805     }
2806
2807   clutter_actor_get_allocation_box (self, &box);
2808
2809   vertices[0].x = box.x1;
2810   vertices[0].y = box.y1;
2811   vertices[0].z = 0;
2812   vertices[1].x = box.x2;
2813   vertices[1].y = box.y1;
2814   vertices[1].z = 0;
2815   vertices[2].x = box.x1;
2816   vertices[2].y = box.y2;
2817   vertices[2].z = 0;
2818   vertices[3].x = box.x2;
2819   vertices[3].y = box.y2;
2820   vertices[3].z = 0;
2821
2822   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2823                                                      &modelview);
2824
2825   cogl_matrix_transform_points (&modelview,
2826                                 3,
2827                                 sizeof (ClutterVertex),
2828                                 vertices,
2829                                 sizeof (ClutterVertex),
2830                                 vertices,
2831                                 4);
2832 }
2833
2834 /**
2835  * clutter_actor_get_abs_allocation_vertices:
2836  * @self: A #ClutterActor
2837  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2838  *   of 4 #ClutterVertex where to store the result.
2839  *
2840  * Calculates the transformed screen coordinates of the four corners of
2841  * the actor; the returned vertices relate to the #ClutterActorBox
2842  * coordinates  as follows:
2843  * <itemizedlist>
2844  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2845  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2846  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2847  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2848  * </itemizedlist>
2849  *
2850  * Since: 0.4
2851  */
2852 void
2853 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2854                                            ClutterVertex  verts[])
2855 {
2856   ClutterActorPrivate *priv;
2857   ClutterActorBox actor_space_allocation;
2858
2859   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2860
2861   priv = self->priv;
2862
2863   /* if the actor needs to be allocated we force a relayout, so that
2864    * the actor allocation box will be valid for
2865    * _clutter_actor_transform_and_project_box()
2866    */
2867   if (priv->needs_allocation)
2868     {
2869       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2870       /* There's nothing meaningful we can do now */
2871       if (!stage)
2872         return;
2873
2874       _clutter_stage_maybe_relayout (stage);
2875     }
2876
2877   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2878    * own coordinate space... */
2879   actor_space_allocation.x1 = 0;
2880   actor_space_allocation.y1 = 0;
2881   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2882   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2883   _clutter_actor_transform_and_project_box (self,
2884                                             &actor_space_allocation,
2885                                             verts);
2886 }
2887
2888 static void
2889 clutter_actor_real_apply_transform (ClutterActor *self,
2890                                     CoglMatrix   *matrix)
2891 {
2892   ClutterActorPrivate *priv = self->priv;
2893
2894   if (!priv->transform_valid)
2895     {
2896       CoglMatrix *transform = &priv->transform;
2897       const ClutterTransformInfo *info;
2898
2899       info = _clutter_actor_get_transform_info_or_defaults (self);
2900
2901       cogl_matrix_init_identity (transform);
2902
2903       cogl_matrix_translate (transform,
2904                              priv->allocation.x1,
2905                              priv->allocation.y1,
2906                              0.0);
2907
2908       if (info->depth)
2909         cogl_matrix_translate (transform, 0, 0, info->depth);
2910
2911       /*
2912        * because the rotation involves translations, we must scale
2913        * before applying the rotations (if we apply the scale after
2914        * the rotations, the translations included in the rotation are
2915        * not scaled and so the entire object will move on the screen
2916        * as a result of rotating it).
2917        */
2918       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2919         {
2920           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2921                                         &info->scale_center,
2922                                         cogl_matrix_scale (transform,
2923                                                            info->scale_x,
2924                                                            info->scale_y,
2925                                                            1.0));
2926         }
2927
2928       if (info->rz_angle)
2929         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2930                                       &info->rz_center,
2931                                       cogl_matrix_rotate (transform,
2932                                                           info->rz_angle,
2933                                                           0, 0, 1.0));
2934
2935       if (info->ry_angle)
2936         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2937                                       &info->ry_center,
2938                                       cogl_matrix_rotate (transform,
2939                                                           info->ry_angle,
2940                                                           0, 1.0, 0));
2941
2942       if (info->rx_angle)
2943         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2944                                       &info->rx_center,
2945                                       cogl_matrix_rotate (transform,
2946                                                           info->rx_angle,
2947                                                           1.0, 0, 0));
2948
2949       if (!clutter_anchor_coord_is_zero (&info->anchor))
2950         {
2951           gfloat x, y, z;
2952
2953           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2954           cogl_matrix_translate (transform, -x, -y, -z);
2955         }
2956
2957       priv->transform_valid = TRUE;
2958     }
2959
2960   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2961 }
2962
2963 /* Applies the transforms associated with this actor to the given
2964  * matrix. */
2965 void
2966 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2967                                           CoglMatrix *matrix)
2968 {
2969   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2970 }
2971
2972 /*
2973  * clutter_actor_apply_relative_transformation_matrix:
2974  * @self: The actor whose coordinate space you want to transform from.
2975  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2976  *            or %NULL if you want to transform all the way to eye coordinates.
2977  * @matrix: A #CoglMatrix to apply the transformation too.
2978  *
2979  * This multiplies a transform with @matrix that will transform coordinates
2980  * from the coordinate space of @self into the coordinate space of @ancestor.
2981  *
2982  * For example if you need a matrix that can transform the local actor
2983  * coordinates of @self into stage coordinates you would pass the actor's stage
2984  * pointer as the @ancestor.
2985  *
2986  * If you pass %NULL then the transformation will take you all the way through
2987  * to eye coordinates. This can be useful if you want to extract the entire
2988  * modelview transform that Clutter applies before applying the projection
2989  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2990  * using cogl_set_modelview_matrix() for example then you would want a matrix
2991  * that transforms into eye coordinates.
2992  *
2993  * <note>This function doesn't initialize the given @matrix, it simply
2994  * multiplies the requested transformation matrix with the existing contents of
2995  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2996  * before calling this function, or you can use
2997  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2998  */
2999 void
3000 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
3001                                                      ClutterActor *ancestor,
3002                                                      CoglMatrix *matrix)
3003 {
3004   ClutterActor *parent;
3005
3006   /* Note we terminate before ever calling stage->apply_transform()
3007    * since that would conceptually be relative to the underlying
3008    * window OpenGL coordinates so we'd need a special @ancestor
3009    * value to represent the fake parent of the stage. */
3010   if (self == ancestor)
3011     return;
3012
3013   parent = clutter_actor_get_parent (self);
3014
3015   if (parent != NULL)
3016     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
3017                                                          matrix);
3018
3019   _clutter_actor_apply_modelview_transform (self, matrix);
3020 }
3021
3022 static void
3023 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
3024                                        ClutterPaintVolume *pv,
3025                                        const char *label,
3026                                        const CoglColor *color)
3027 {
3028   static CoglPipeline *outline = NULL;
3029   CoglPrimitive *prim;
3030   ClutterVertex line_ends[12 * 2];
3031   int n_vertices;
3032   CoglContext *ctx =
3033     clutter_backend_get_cogl_context (clutter_get_default_backend ());
3034   /* XXX: at some point we'll query this from the stage but we can't
3035    * do that until the osx backend uses Cogl natively. */
3036   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
3037
3038   if (outline == NULL)
3039     outline = cogl_pipeline_new (ctx);
3040
3041   _clutter_paint_volume_complete (pv);
3042
3043   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3044
3045   /* Front face */
3046   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3047   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3048   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3049   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3050
3051   if (!pv->is_2d)
3052     {
3053       /* Back face */
3054       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3055       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3056       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3057       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3058
3059       /* Lines connecting front face to back face */
3060       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3061       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3062       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3063       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3064     }
3065
3066   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3067                                 n_vertices,
3068                                 (CoglVertexP3 *)line_ends);
3069
3070   cogl_pipeline_set_color (outline, color);
3071   cogl_framebuffer_draw_primitive (fb, outline, prim);
3072   cogl_object_unref (prim);
3073
3074   if (label)
3075     {
3076       PangoLayout *layout;
3077       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3078       pango_layout_set_text (layout, label, -1);
3079       cogl_pango_render_layout (layout,
3080                                 pv->vertices[0].x,
3081                                 pv->vertices[0].y,
3082                                 color,
3083                                 0);
3084       g_object_unref (layout);
3085     }
3086 }
3087
3088 static void
3089 _clutter_actor_draw_paint_volume (ClutterActor *self)
3090 {
3091   ClutterPaintVolume *pv;
3092   CoglColor color;
3093
3094   pv = _clutter_actor_get_paint_volume_mutable (self);
3095   if (!pv)
3096     {
3097       gfloat width, height;
3098       ClutterPaintVolume fake_pv;
3099
3100       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3101       _clutter_paint_volume_init_static (&fake_pv, stage);
3102
3103       clutter_actor_get_size (self, &width, &height);
3104       clutter_paint_volume_set_width (&fake_pv, width);
3105       clutter_paint_volume_set_height (&fake_pv, height);
3106
3107       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3108       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3109                                              _clutter_actor_get_debug_name (self),
3110                                              &color);
3111
3112       clutter_paint_volume_free (&fake_pv);
3113     }
3114   else
3115     {
3116       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3117       _clutter_actor_draw_paint_volume_full (self, pv,
3118                                              _clutter_actor_get_debug_name (self),
3119                                              &color);
3120     }
3121 }
3122
3123 static void
3124 _clutter_actor_paint_cull_result (ClutterActor *self,
3125                                   gboolean success,
3126                                   ClutterCullResult result)
3127 {
3128   ClutterPaintVolume *pv;
3129   CoglColor color;
3130
3131   if (success)
3132     {
3133       if (result == CLUTTER_CULL_RESULT_IN)
3134         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3135       else if (result == CLUTTER_CULL_RESULT_OUT)
3136         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3137       else
3138         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3139     }
3140   else
3141     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3142
3143   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3144     _clutter_actor_draw_paint_volume_full (self, pv,
3145                                            _clutter_actor_get_debug_name (self),
3146                                            &color);
3147   else
3148     {
3149       PangoLayout *layout;
3150       char *label =
3151         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3152       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3153       cogl_set_source_color (&color);
3154
3155       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3156       pango_layout_set_text (layout, label, -1);
3157       cogl_pango_render_layout (layout,
3158                                 0,
3159                                 0,
3160                                 &color,
3161                                 0);
3162       g_free (label);
3163       g_object_unref (layout);
3164     }
3165 }
3166
3167 static int clone_paint_level = 0;
3168
3169 void
3170 _clutter_actor_push_clone_paint (void)
3171 {
3172   clone_paint_level++;
3173 }
3174
3175 void
3176 _clutter_actor_pop_clone_paint (void)
3177 {
3178   clone_paint_level--;
3179 }
3180
3181 static gboolean
3182 in_clone_paint (void)
3183 {
3184   return clone_paint_level > 0;
3185 }
3186
3187 /* Returns TRUE if the actor can be ignored */
3188 /* FIXME: we should return a ClutterCullResult, and
3189  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3190  * means there's no point in trying to cull descendants of the current
3191  * node. */
3192 static gboolean
3193 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3194 {
3195   ClutterActorPrivate *priv = self->priv;
3196   ClutterActor *stage;
3197   const ClutterPlane *stage_clip;
3198
3199   if (!priv->last_paint_volume_valid)
3200     {
3201       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3202                     "->last_paint_volume_valid == FALSE",
3203                     _clutter_actor_get_debug_name (self));
3204       return FALSE;
3205     }
3206
3207   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3208     return FALSE;
3209
3210   stage = _clutter_actor_get_stage_internal (self);
3211   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3212   if (G_UNLIKELY (!stage_clip))
3213     {
3214       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3215                     "No stage clip set",
3216                     _clutter_actor_get_debug_name (self));
3217       return FALSE;
3218     }
3219
3220   if (cogl_get_draw_framebuffer () !=
3221       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3222     {
3223       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3224                     "Current framebuffer doesn't correspond to stage",
3225                     _clutter_actor_get_debug_name (self));
3226       return FALSE;
3227     }
3228
3229   *result_out =
3230     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3231   return TRUE;
3232 }
3233
3234 static void
3235 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3236 {
3237   ClutterActorPrivate *priv = self->priv;
3238   const ClutterPaintVolume *pv;
3239
3240   if (priv->last_paint_volume_valid)
3241     {
3242       clutter_paint_volume_free (&priv->last_paint_volume);
3243       priv->last_paint_volume_valid = FALSE;
3244     }
3245
3246   pv = clutter_actor_get_paint_volume (self);
3247   if (!pv)
3248     {
3249       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3250                     "Actor failed to report a paint volume",
3251                     _clutter_actor_get_debug_name (self));
3252       return;
3253     }
3254
3255   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3256
3257   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3258                                             NULL); /* eye coordinates */
3259
3260   priv->last_paint_volume_valid = TRUE;
3261 }
3262
3263 static inline gboolean
3264 actor_has_shader_data (ClutterActor *self)
3265 {
3266   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3267 }
3268
3269 guint32
3270 _clutter_actor_get_pick_id (ClutterActor *self)
3271 {
3272   if (self->priv->pick_id < 0)
3273     return 0;
3274
3275   return self->priv->pick_id;
3276 }
3277
3278 /* This is the same as clutter_actor_add_effect except that it doesn't
3279    queue a redraw and it doesn't notify on the effect property */
3280 static void
3281 _clutter_actor_add_effect_internal (ClutterActor  *self,
3282                                     ClutterEffect *effect)
3283 {
3284   ClutterActorPrivate *priv = self->priv;
3285
3286   if (priv->effects == NULL)
3287     {
3288       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3289       priv->effects->actor = self;
3290     }
3291
3292   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3293 }
3294
3295 /* This is the same as clutter_actor_remove_effect except that it doesn't
3296    queue a redraw and it doesn't notify on the effect property */
3297 static void
3298 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3299                                        ClutterEffect *effect)
3300 {
3301   ClutterActorPrivate *priv = self->priv;
3302
3303   if (priv->effects == NULL)
3304     return;
3305
3306   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3307
3308   if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3309     g_clear_object (&priv->effects);
3310 }
3311
3312 static gboolean
3313 needs_flatten_effect (ClutterActor *self)
3314 {
3315   ClutterActorPrivate *priv = self->priv;
3316
3317   if (G_UNLIKELY (clutter_paint_debug_flags &
3318                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3319     return FALSE;
3320
3321   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3322     return TRUE;
3323   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3324     {
3325       if (clutter_actor_get_paint_opacity (self) < 255 &&
3326           clutter_actor_has_overlaps (self))
3327         return TRUE;
3328     }
3329
3330   return FALSE;
3331 }
3332
3333 static void
3334 add_or_remove_flatten_effect (ClutterActor *self)
3335 {
3336   ClutterActorPrivate *priv = self->priv;
3337
3338   /* Add or remove the flatten effect depending on the
3339      offscreen-redirect property. */
3340   if (needs_flatten_effect (self))
3341     {
3342       if (priv->flatten_effect == NULL)
3343         {
3344           ClutterActorMeta *actor_meta;
3345           gint priority;
3346
3347           priv->flatten_effect = _clutter_flatten_effect_new ();
3348           /* Keep a reference to the effect so that we can queue
3349              redraws from it */
3350           g_object_ref_sink (priv->flatten_effect);
3351
3352           /* Set the priority of the effect to high so that it will
3353              always be applied to the actor first. It uses an internal
3354              priority so that it won't be visible to applications */
3355           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3356           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3357           _clutter_actor_meta_set_priority (actor_meta, priority);
3358
3359           /* This will add the effect without queueing a redraw */
3360           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3361         }
3362     }
3363   else
3364     {
3365       if (priv->flatten_effect != NULL)
3366         {
3367           /* Destroy the effect so that it will lose its fbo cache of
3368              the actor */
3369           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3370           g_clear_object (&priv->flatten_effect);
3371         }
3372     }
3373 }
3374
3375 static void
3376 clutter_actor_real_paint (ClutterActor *actor)
3377 {
3378   ClutterActorPrivate *priv = actor->priv;
3379   ClutterActor *iter;
3380
3381   for (iter = priv->first_child;
3382        iter != NULL;
3383        iter = iter->priv->next_sibling)
3384     {
3385       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3386                     _clutter_actor_get_debug_name (iter),
3387                     _clutter_actor_get_debug_name (actor),
3388                     iter->priv->allocation.x1,
3389                     iter->priv->allocation.y1,
3390                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3391                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3392
3393       clutter_actor_paint (iter);
3394     }
3395 }
3396
3397 static gboolean
3398 clutter_actor_paint_node (ClutterActor     *actor,
3399                           ClutterPaintNode *root)
3400 {
3401   ClutterActorPrivate *priv = actor->priv;
3402
3403   if (root == NULL)
3404     return FALSE;
3405
3406   if (priv->bg_color_set &&
3407       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3408     {
3409       ClutterPaintNode *node;
3410       ClutterColor bg_color;
3411       ClutterActorBox box;
3412
3413       box.x1 = 0.f;
3414       box.y1 = 0.f;
3415       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3416       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3417
3418       bg_color = priv->bg_color;
3419       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3420                      * priv->bg_color.alpha
3421                      / 255;
3422
3423       node = clutter_color_node_new (&bg_color);
3424       clutter_paint_node_set_name (node, "backgroundColor");
3425       clutter_paint_node_add_rectangle (node, &box);
3426       clutter_paint_node_add_child (root, node);
3427       clutter_paint_node_unref (node);
3428     }
3429
3430   if (priv->content != NULL)
3431     _clutter_content_paint_content (priv->content, actor, root);
3432
3433   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3434     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3435
3436   if (clutter_paint_node_get_n_children (root) == 0)
3437     return FALSE;
3438
3439 #ifdef CLUTTER_ENABLE_DEBUG
3440   if (CLUTTER_HAS_DEBUG (PAINT))
3441     {
3442       /* dump the tree only if we have one */
3443       _clutter_paint_node_dump_tree (root);
3444     }
3445 #endif /* CLUTTER_ENABLE_DEBUG */
3446
3447   _clutter_paint_node_paint (root);
3448
3449 #if 0
3450   /* XXX: Uncomment this when we disable emitting the paint signal */
3451   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3452 #endif
3453
3454   return TRUE;
3455 }
3456
3457 /**
3458  * clutter_actor_paint:
3459  * @self: A #ClutterActor
3460  *
3461  * Renders the actor to display.
3462  *
3463  * This function should not be called directly by applications.
3464  * Call clutter_actor_queue_redraw() to queue paints, instead.
3465  *
3466  * This function is context-aware, and will either cause a
3467  * regular paint or a pick paint.
3468  *
3469  * This function will emit the #ClutterActor::paint signal or
3470  * the #ClutterActor::pick signal, depending on the context.
3471  *
3472  * This function does not paint the actor if the actor is set to 0,
3473  * unless it is performing a pick paint.
3474  */
3475 void
3476 clutter_actor_paint (ClutterActor *self)
3477 {
3478   ClutterActorPrivate *priv;
3479   ClutterPickMode pick_mode;
3480   gboolean clip_set = FALSE;
3481   gboolean shader_applied = FALSE;
3482
3483   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3484                           "Actor real-paint counter",
3485                           "Increments each time any actor is painted",
3486                           0 /* no application private data */);
3487   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3488                           "Actor pick-paint counter",
3489                           "Increments each time any actor is painted "
3490                           "for picking",
3491                           0 /* no application private data */);
3492
3493   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3494
3495   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3496     return;
3497
3498   priv = self->priv;
3499
3500   pick_mode = _clutter_context_get_pick_mode ();
3501
3502   if (pick_mode == CLUTTER_PICK_NONE)
3503     priv->propagated_one_redraw = FALSE;
3504
3505   /* It's an important optimization that we consider painting of
3506    * actors with 0 opacity to be a NOP... */
3507   if (pick_mode == CLUTTER_PICK_NONE &&
3508       /* ignore top-levels, since they might be transparent */
3509       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3510       /* Use the override opacity if its been set */
3511       ((priv->opacity_override >= 0) ?
3512        priv->opacity_override : priv->opacity) == 0)
3513     return;
3514
3515   /* if we aren't paintable (not in a toplevel with all
3516    * parents paintable) then do nothing.
3517    */
3518   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3519     return;
3520
3521   /* mark that we are in the paint process */
3522   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3523
3524   cogl_push_matrix();
3525
3526   if (priv->enable_model_view_transform)
3527     {
3528       CoglMatrix matrix;
3529
3530       /* XXX: It could be better to cache the modelview with the actor
3531        * instead of progressively building up the transformations on
3532        * the matrix stack every time we paint. */
3533       cogl_get_modelview_matrix (&matrix);
3534       _clutter_actor_apply_modelview_transform (self, &matrix);
3535
3536 #ifdef CLUTTER_ENABLE_DEBUG
3537       /* Catch when out-of-band transforms have been made by actors not as part
3538        * of an apply_transform vfunc... */
3539       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3540         {
3541           CoglMatrix expected_matrix;
3542
3543           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3544                                                              &expected_matrix);
3545
3546           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3547             {
3548               GString *buf = g_string_sized_new (1024);
3549               ClutterActor *parent;
3550
3551               parent = self;
3552               while (parent != NULL)
3553                 {
3554                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3555
3556                   if (parent->priv->parent != NULL)
3557                     g_string_append (buf, "->");
3558
3559                   parent = parent->priv->parent;
3560                 }
3561
3562               g_warning ("Unexpected transform found when painting actor "
3563                          "\"%s\". This will be caused by one of the actor's "
3564                          "ancestors (%s) using the Cogl API directly to transform "
3565                          "children instead of using ::apply_transform().",
3566                          _clutter_actor_get_debug_name (self),
3567                          buf->str);
3568
3569               g_string_free (buf, TRUE);
3570             }
3571         }
3572 #endif /* CLUTTER_ENABLE_DEBUG */
3573
3574       cogl_set_modelview_matrix (&matrix);
3575     }
3576
3577   if (priv->has_clip)
3578     {
3579       cogl_clip_push_rectangle (priv->clip.x,
3580                                 priv->clip.y,
3581                                 priv->clip.x + priv->clip.width,
3582                                 priv->clip.y + priv->clip.height);
3583       clip_set = TRUE;
3584     }
3585   else if (priv->clip_to_allocation)
3586     {
3587       gfloat width, height;
3588
3589       width  = priv->allocation.x2 - priv->allocation.x1;
3590       height = priv->allocation.y2 - priv->allocation.y1;
3591
3592       cogl_clip_push_rectangle (0, 0, width, height);
3593       clip_set = TRUE;
3594     }
3595
3596   if (pick_mode == CLUTTER_PICK_NONE)
3597     {
3598       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3599
3600       /* We check whether we need to add the flatten effect before
3601          each paint so that we can avoid having a mechanism for
3602          applications to notify when the value of the
3603          has_overlaps virtual changes. */
3604       add_or_remove_flatten_effect (self);
3605     }
3606   else
3607     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3608
3609   /* We save the current paint volume so that the next time the
3610    * actor queues a redraw we can constrain the redraw to just
3611    * cover the union of the new bounding box and the old.
3612    *
3613    * We also fetch the current paint volume to perform culling so
3614    * we can avoid painting actors outside the current clip region.
3615    *
3616    * If we are painting inside a clone, we should neither update
3617    * the paint volume or use it to cull painting, since the paint
3618    * box represents the location of the source actor on the
3619    * screen.
3620    *
3621    * XXX: We are starting to do a lot of vertex transforms on
3622    * the CPU in a typical paint, so at some point we should
3623    * audit these and consider caching some things.
3624    *
3625    * NB: We don't perform culling while picking at this point because
3626    * clutter-stage.c doesn't setup the clipping planes appropriately.
3627    *
3628    * NB: We don't want to update the last-paint-volume during picking
3629    * because the last-paint-volume is used to determine the old screen
3630    * space location of an actor that has moved so we can know the
3631    * minimal region to redraw to clear an old view of the actor. If we
3632    * update this during picking then by the time we come around to
3633    * paint then the last-paint-volume would likely represent the new
3634    * actor position not the old.
3635    */
3636   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3637     {
3638       gboolean success;
3639       /* annoyingly gcc warns if uninitialized even though
3640        * the initialization is redundant :-( */
3641       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3642
3643       if (G_LIKELY ((clutter_paint_debug_flags &
3644                      (CLUTTER_DEBUG_DISABLE_CULLING |
3645                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3646                     (CLUTTER_DEBUG_DISABLE_CULLING |
3647                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3648         _clutter_actor_update_last_paint_volume (self);
3649
3650       success = cull_actor (self, &result);
3651
3652       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3653         _clutter_actor_paint_cull_result (self, success, result);
3654       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3655         goto done;
3656     }
3657
3658   if (priv->effects == NULL)
3659     {
3660       if (pick_mode == CLUTTER_PICK_NONE &&
3661           actor_has_shader_data (self))
3662         {
3663           _clutter_actor_shader_pre_paint (self, FALSE);
3664           shader_applied = TRUE;
3665         }
3666
3667       priv->next_effect_to_paint = NULL;
3668     }
3669   else
3670     priv->next_effect_to_paint =
3671       _clutter_meta_group_peek_metas (priv->effects);
3672
3673   clutter_actor_continue_paint (self);
3674
3675   if (shader_applied)
3676     _clutter_actor_shader_post_paint (self);
3677
3678   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3679                   pick_mode == CLUTTER_PICK_NONE))
3680     _clutter_actor_draw_paint_volume (self);
3681
3682 done:
3683   /* If we make it here then the actor has run through a complete
3684      paint run including all the effects so it's no longer dirty */
3685   if (pick_mode == CLUTTER_PICK_NONE)
3686     priv->is_dirty = FALSE;
3687
3688   if (clip_set)
3689     cogl_clip_pop();
3690
3691   cogl_pop_matrix();
3692
3693   /* paint sequence complete */
3694   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3695 }
3696
3697 /**
3698  * clutter_actor_continue_paint:
3699  * @self: A #ClutterActor
3700  *
3701  * Run the next stage of the paint sequence. This function should only
3702  * be called within the implementation of the ‘run’ virtual of a
3703  * #ClutterEffect. It will cause the run method of the next effect to
3704  * be applied, or it will paint the actual actor if the current effect
3705  * is the last effect in the chain.
3706  *
3707  * Since: 1.8
3708  */
3709 void
3710 clutter_actor_continue_paint (ClutterActor *self)
3711 {
3712   ClutterActorPrivate *priv;
3713
3714   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3715   /* This should only be called from with in the ‘run’ implementation
3716      of a ClutterEffect */
3717   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3718
3719   priv = self->priv;
3720
3721   /* Skip any effects that are disabled */
3722   while (priv->next_effect_to_paint &&
3723          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3724     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3725
3726   /* If this has come from the last effect then we'll just paint the
3727      actual actor */
3728   if (priv->next_effect_to_paint == NULL)
3729     {
3730       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3731         {
3732           ClutterPaintNode *dummy;
3733
3734           /* XXX - this will go away in 2.0, when we can get rid of this
3735            * stuff and switch to a pure retained render tree of PaintNodes
3736            * for the entire frame, starting from the Stage; the paint()
3737            * virtual function can then be called directly.
3738            */
3739           dummy = _clutter_dummy_node_new (self);
3740           clutter_paint_node_set_name (dummy, "Root");
3741
3742           /* XXX - for 1.12, we use the return value of paint_node() to
3743            * decide whether we should emit the ::paint signal.
3744            */
3745           clutter_actor_paint_node (self, dummy);
3746           clutter_paint_node_unref (dummy);
3747
3748           g_signal_emit (self, actor_signals[PAINT], 0);
3749         }
3750       else
3751         {
3752           ClutterColor col = { 0, };
3753
3754           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3755
3756           /* Actor will then paint silhouette of itself in supplied
3757            * color.  See clutter_stage_get_actor_at_pos() for where
3758            * picking is enabled.
3759            */
3760           g_signal_emit (self, actor_signals[PICK], 0, &col);
3761         }
3762     }
3763   else
3764     {
3765       ClutterEffect *old_current_effect;
3766       ClutterEffectPaintFlags run_flags = 0;
3767
3768       /* Cache the current effect so that we can put it back before
3769          returning */
3770       old_current_effect = priv->current_effect;
3771
3772       priv->current_effect = priv->next_effect_to_paint->data;
3773       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3774
3775       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3776         {
3777           if (priv->is_dirty)
3778             {
3779               /* If there's an effect queued with this redraw then all
3780                  effects up to that one will be considered dirty. It
3781                  is expected the queued effect will paint the cached
3782                  image and not call clutter_actor_continue_paint again
3783                  (although it should work ok if it does) */
3784               if (priv->effect_to_redraw == NULL ||
3785                   priv->current_effect != priv->effect_to_redraw)
3786                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3787             }
3788
3789           _clutter_effect_paint (priv->current_effect, run_flags);
3790         }
3791       else
3792         {
3793           /* We can't determine when an actor has been modified since
3794              its last pick so lets just assume it has always been
3795              modified */
3796           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3797
3798           _clutter_effect_pick (priv->current_effect, run_flags);
3799         }
3800
3801       priv->current_effect = old_current_effect;
3802     }
3803 }
3804
3805 static ClutterActorTraverseVisitFlags
3806 invalidate_queue_redraw_entry (ClutterActor *self,
3807                                int           depth,
3808                                gpointer      user_data)
3809 {
3810   ClutterActorPrivate *priv = self->priv;
3811
3812   if (priv->queue_redraw_entry != NULL)
3813     {
3814       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3815       priv->queue_redraw_entry = NULL;
3816     }
3817
3818   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3819 }
3820
3821 static inline void
3822 remove_child (ClutterActor *self,
3823               ClutterActor *child)
3824 {
3825   ClutterActor *prev_sibling, *next_sibling;
3826
3827   prev_sibling = child->priv->prev_sibling;
3828   next_sibling = child->priv->next_sibling;
3829
3830   if (prev_sibling != NULL)
3831     prev_sibling->priv->next_sibling = next_sibling;
3832
3833   if (next_sibling != NULL)
3834     next_sibling->priv->prev_sibling = prev_sibling;
3835
3836   if (self->priv->first_child == child)
3837     self->priv->first_child = next_sibling;
3838
3839   if (self->priv->last_child == child)
3840     self->priv->last_child = prev_sibling;
3841
3842   child->priv->parent = NULL;
3843   child->priv->prev_sibling = NULL;
3844   child->priv->next_sibling = NULL;
3845 }
3846
3847 typedef enum {
3848   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3849   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3850   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3851   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3852   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3853   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3854
3855   /* default flags for public API */
3856   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3857                                     REMOVE_CHILD_EMIT_PARENT_SET |
3858                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3859                                     REMOVE_CHILD_CHECK_STATE |
3860                                     REMOVE_CHILD_FLUSH_QUEUE |
3861                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3862
3863   /* flags for legacy/deprecated API */
3864   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3865                                     REMOVE_CHILD_FLUSH_QUEUE |
3866                                     REMOVE_CHILD_EMIT_PARENT_SET |
3867                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3868 } ClutterActorRemoveChildFlags;
3869
3870 /*< private >
3871  * clutter_actor_remove_child_internal:
3872  * @self: a #ClutterActor
3873  * @child: the child of @self that has to be removed
3874  * @flags: control the removal operations
3875  *
3876  * Removes @child from the list of children of @self.
3877  */
3878 static void
3879 clutter_actor_remove_child_internal (ClutterActor                 *self,
3880                                      ClutterActor                 *child,
3881                                      ClutterActorRemoveChildFlags  flags)
3882 {
3883   ClutterActor *old_first, *old_last;
3884   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3885   gboolean flush_queue;
3886   gboolean notify_first_last;
3887   gboolean was_mapped;
3888
3889   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3890   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3891   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3892   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3893   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3894   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3895
3896   g_object_freeze_notify (G_OBJECT (self));
3897
3898   if (destroy_meta)
3899     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3900
3901   if (check_state)
3902     {
3903       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3904
3905       /* we need to unrealize *before* we set parent_actor to NULL,
3906        * because in an unrealize method actors are dissociating from the
3907        * stage, which means they need to be able to
3908        * clutter_actor_get_stage().
3909        *
3910        * yhis should unmap and unrealize, unless we're reparenting.
3911        */
3912       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3913     }
3914   else
3915     was_mapped = FALSE;
3916
3917   if (flush_queue)
3918     {
3919       /* We take this opportunity to invalidate any queue redraw entry
3920        * associated with the actor and descendants since we won't be able to
3921        * determine the appropriate stage after this.
3922        *
3923        * we do this after we updated the mapped state because actors might
3924        * end up queueing redraws inside their mapped/unmapped virtual
3925        * functions, and if we invalidate the redraw entry we could end up
3926        * with an inconsistent state and weird memory corruption. see
3927        * bugs:
3928        *
3929        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3930        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3931        */
3932       _clutter_actor_traverse (child,
3933                                0,
3934                                invalidate_queue_redraw_entry,
3935                                NULL,
3936                                NULL);
3937     }
3938
3939   old_first = self->priv->first_child;
3940   old_last = self->priv->last_child;
3941
3942   remove_child (self, child);
3943
3944   self->priv->n_children -= 1;
3945
3946   self->priv->age += 1;
3947
3948   /* if the child that got removed was visible and set to
3949    * expand then we want to reset the parent's state in
3950    * case the child was the only thing that was making it
3951    * expand.
3952    */
3953   if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
3954       (child->priv->needs_compute_expand ||
3955        child->priv->needs_x_expand ||
3956        child->priv->needs_y_expand))
3957     {
3958       clutter_actor_queue_compute_expand (self);
3959     }
3960
3961   /* clutter_actor_reparent() will emit ::parent-set for us */
3962   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3963     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3964
3965   /* if the child was mapped then we need to relayout ourselves to account
3966    * for the removed child
3967    */
3968   if (was_mapped)
3969     clutter_actor_queue_relayout (self);
3970
3971   /* we need to emit the signal before dropping the reference */
3972   if (emit_actor_removed)
3973     g_signal_emit_by_name (self, "actor-removed", child);
3974
3975   if (notify_first_last)
3976     {
3977       if (old_first != self->priv->first_child)
3978         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3979
3980       if (old_last != self->priv->last_child)
3981         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3982     }
3983
3984   g_object_thaw_notify (G_OBJECT (self));
3985
3986   /* remove the reference we acquired in clutter_actor_add_child() */
3987   g_object_unref (child);
3988 }
3989
3990 static const ClutterTransformInfo default_transform_info = {
3991   0.0, { 0, },          /* rotation-x */
3992   0.0, { 0, },          /* rotation-y */
3993   0.0, { 0, },          /* rotation-z */
3994
3995   1.0, 1.0, { 0, },     /* scale */
3996
3997   { 0, },               /* anchor */
3998
3999   0.0,                  /* depth */
4000 };
4001
4002 /*< private >
4003  * _clutter_actor_get_transform_info_or_defaults:
4004  * @self: a #ClutterActor
4005  *
4006  * Retrieves the ClutterTransformInfo structure associated to an actor.
4007  *
4008  * If the actor does not have a ClutterTransformInfo structure associated
4009  * to it, then the default structure will be returned.
4010  *
4011  * This function should only be used for getters.
4012  *
4013  * Return value: a const pointer to the ClutterTransformInfo structure
4014  */
4015 const ClutterTransformInfo *
4016 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
4017 {
4018   ClutterTransformInfo *info;
4019
4020   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4021   if (info != NULL)
4022     return info;
4023
4024   return &default_transform_info;
4025 }
4026
4027 static void
4028 clutter_transform_info_free (gpointer data)
4029 {
4030   if (data != NULL)
4031     g_slice_free (ClutterTransformInfo, data);
4032 }
4033
4034 /*< private >
4035  * _clutter_actor_get_transform_info:
4036  * @self: a #ClutterActor
4037  *
4038  * Retrieves a pointer to the ClutterTransformInfo structure.
4039  *
4040  * If the actor does not have a ClutterTransformInfo associated to it, one
4041  * will be created and initialized to the default values.
4042  *
4043  * This function should be used for setters.
4044  *
4045  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
4046  * instead.
4047  *
4048  * Return value: (transfer none): a pointer to the ClutterTransformInfo
4049  *   structure
4050  */
4051 ClutterTransformInfo *
4052 _clutter_actor_get_transform_info (ClutterActor *self)
4053 {
4054   ClutterTransformInfo *info;
4055
4056   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4057   if (info == NULL)
4058     {
4059       info = g_slice_new (ClutterTransformInfo);
4060
4061       *info = default_transform_info;
4062
4063       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4064                                info,
4065                                clutter_transform_info_free);
4066     }
4067
4068   return info;
4069 }
4070
4071 /*< private >
4072  * clutter_actor_set_rotation_angle_internal:
4073  * @self: a #ClutterActor
4074  * @axis: the axis of the angle to change
4075  * @angle: the angle of rotation
4076  *
4077  * Sets the rotation angle on the given axis without affecting the
4078  * rotation center point.
4079  */
4080 static inline void
4081 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
4082                                            ClutterRotateAxis  axis,
4083                                            gdouble            angle)
4084 {
4085   GObject *obj = G_OBJECT (self);
4086   ClutterTransformInfo *info;
4087
4088   info = _clutter_actor_get_transform_info (self);
4089
4090   g_object_freeze_notify (obj);
4091
4092   switch (axis)
4093     {
4094     case CLUTTER_X_AXIS:
4095       info->rx_angle = angle;
4096       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4097       break;
4098
4099     case CLUTTER_Y_AXIS:
4100       info->ry_angle = angle;
4101       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4102       break;
4103
4104     case CLUTTER_Z_AXIS:
4105       info->rz_angle = angle;
4106       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4107       break;
4108     }
4109
4110   self->priv->transform_valid = FALSE;
4111
4112   g_object_thaw_notify (obj);
4113
4114   clutter_actor_queue_redraw (self);
4115 }
4116
4117 static inline void
4118 clutter_actor_set_rotation_angle (ClutterActor      *self,
4119                                   ClutterRotateAxis  axis,
4120                                   gdouble            angle)
4121 {
4122   const ClutterTransformInfo *info;
4123   const double *cur_angle_p = NULL;
4124   GParamSpec *pspec = NULL;
4125
4126   info = _clutter_actor_get_transform_info_or_defaults (self);
4127
4128   switch (axis)
4129     {
4130     case CLUTTER_X_AXIS:
4131       cur_angle_p = &info->rx_angle;
4132       pspec = obj_props[PROP_ROTATION_ANGLE_X];
4133       break;
4134
4135     case CLUTTER_Y_AXIS:
4136       cur_angle_p = &info->ry_angle;
4137       pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4138       break;
4139
4140     case CLUTTER_Z_AXIS:
4141       cur_angle_p = &info->rz_angle;
4142       pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4143       break;
4144     }
4145
4146   g_assert (pspec != NULL);
4147   g_assert (cur_angle_p != NULL);
4148
4149   if (_clutter_actor_get_transition (self, pspec) == NULL)
4150     _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4151   else
4152     _clutter_actor_update_transition (self, pspec, angle);
4153
4154   clutter_actor_queue_redraw (self);
4155 }
4156
4157 /*< private >
4158  * clutter_actor_set_rotation_center_internal:
4159  * @self: a #ClutterActor
4160  * @axis: the axis of the center to change
4161  * @center: the coordinates of the rotation center
4162  *
4163  * Sets the rotation center on the given axis without affecting the
4164  * rotation angle.
4165  */
4166 static inline void
4167 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4168                                             ClutterRotateAxis    axis,
4169                                             const ClutterVertex *center)
4170 {
4171   GObject *obj = G_OBJECT (self);
4172   ClutterTransformInfo *info;
4173   ClutterVertex v = { 0, 0, 0 };
4174
4175   info = _clutter_actor_get_transform_info (self);
4176
4177   if (center != NULL)
4178     v = *center;
4179
4180   g_object_freeze_notify (obj);
4181
4182   switch (axis)
4183     {
4184     case CLUTTER_X_AXIS:
4185       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4186       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4187       break;
4188
4189     case CLUTTER_Y_AXIS:
4190       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4191       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4192       break;
4193
4194     case CLUTTER_Z_AXIS:
4195       /* if the previously set rotation center was fractional, then
4196        * setting explicit coordinates will have to notify the
4197        * :rotation-center-z-gravity property as well
4198        */
4199       if (info->rz_center.is_fractional)
4200         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4201
4202       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4203       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4204       break;
4205     }
4206
4207   self->priv->transform_valid = FALSE;
4208
4209   g_object_thaw_notify (obj);
4210
4211   clutter_actor_queue_redraw (self);
4212 }
4213
4214 static void
4215 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4216                                          double factor,
4217                                          GParamSpec *pspec)
4218 {
4219   GObject *obj = G_OBJECT (self);
4220   ClutterTransformInfo *info;
4221
4222   info = _clutter_actor_get_transform_info (self);
4223
4224   if (pspec == obj_props[PROP_SCALE_X])
4225     info->scale_x = factor;
4226   else
4227     info->scale_y = factor;
4228
4229   self->priv->transform_valid = FALSE;
4230   clutter_actor_queue_redraw (self);
4231   g_object_notify_by_pspec (obj, pspec);
4232 }
4233
4234 static inline void
4235 clutter_actor_set_scale_factor (ClutterActor      *self,
4236                                 ClutterRotateAxis  axis,
4237                                 gdouble            factor)
4238 {
4239   const ClutterTransformInfo *info;
4240   const double *scale_p = NULL;
4241   GParamSpec *pspec = NULL;
4242
4243   info = _clutter_actor_get_transform_info_or_defaults (self);
4244
4245   switch (axis)
4246     {
4247     case CLUTTER_X_AXIS:
4248       pspec = obj_props[PROP_SCALE_X];
4249       scale_p = &info->scale_x;
4250       break;
4251
4252     case CLUTTER_Y_AXIS:
4253       pspec = obj_props[PROP_SCALE_Y];
4254       scale_p = &info->scale_y;
4255       break;
4256
4257     case CLUTTER_Z_AXIS:
4258       break;
4259     }
4260
4261   g_assert (pspec != NULL);
4262   g_assert (scale_p != NULL);
4263
4264   if (_clutter_actor_get_transition (self, pspec) == NULL)
4265     _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4266   else
4267     _clutter_actor_update_transition (self, pspec, factor);
4268
4269   clutter_actor_queue_redraw (self);
4270 }
4271
4272 static inline void
4273 clutter_actor_set_scale_center (ClutterActor      *self,
4274                                 ClutterRotateAxis  axis,
4275                                 gfloat             coord)
4276 {
4277   GObject *obj = G_OBJECT (self);
4278   ClutterTransformInfo *info;
4279   gfloat center_x, center_y;
4280
4281   info = _clutter_actor_get_transform_info (self);
4282
4283   g_object_freeze_notify (obj);
4284
4285   /* get the current scale center coordinates */
4286   clutter_anchor_coord_get_units (self, &info->scale_center,
4287                                   &center_x,
4288                                   &center_y,
4289                                   NULL);
4290
4291   /* we need to notify this too, because setting explicit coordinates will
4292    * change the gravity as a side effect
4293    */
4294   if (info->scale_center.is_fractional)
4295     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4296
4297   switch (axis)
4298     {
4299     case CLUTTER_X_AXIS:
4300       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4301       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4302       break;
4303
4304     case CLUTTER_Y_AXIS:
4305       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4306       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4307       break;
4308
4309     default:
4310       g_assert_not_reached ();
4311     }
4312
4313   self->priv->transform_valid = FALSE;
4314
4315   clutter_actor_queue_redraw (self);
4316
4317   g_object_thaw_notify (obj);
4318 }
4319
4320 static inline void
4321 clutter_actor_set_scale_gravity (ClutterActor   *self,
4322                                  ClutterGravity  gravity)
4323 {
4324   ClutterTransformInfo *info;
4325   GObject *obj;
4326
4327   info = _clutter_actor_get_transform_info (self);
4328   obj = G_OBJECT (self);
4329
4330   if (gravity == CLUTTER_GRAVITY_NONE)
4331     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4332   else
4333     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4334
4335   self->priv->transform_valid = FALSE;
4336
4337   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4338   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4339   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4340
4341   clutter_actor_queue_redraw (self);
4342 }
4343
4344 static inline void
4345 clutter_actor_set_anchor_coord (ClutterActor      *self,
4346                                 ClutterRotateAxis  axis,
4347                                 gfloat             coord)
4348 {
4349   GObject *obj = G_OBJECT (self);
4350   ClutterTransformInfo *info;
4351   gfloat anchor_x, anchor_y;
4352
4353   info = _clutter_actor_get_transform_info (self);
4354
4355   g_object_freeze_notify (obj);
4356
4357   clutter_anchor_coord_get_units (self, &info->anchor,
4358                                   &anchor_x,
4359                                   &anchor_y,
4360                                   NULL);
4361
4362   if (info->anchor.is_fractional)
4363     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4364
4365   switch (axis)
4366     {
4367     case CLUTTER_X_AXIS:
4368       clutter_anchor_coord_set_units (&info->anchor,
4369                                       coord,
4370                                       anchor_y,
4371                                       0.0);
4372       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4373       break;
4374
4375     case CLUTTER_Y_AXIS:
4376       clutter_anchor_coord_set_units (&info->anchor,
4377                                       anchor_x,
4378                                       coord,
4379                                       0.0);
4380       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4381       break;
4382
4383     default:
4384       g_assert_not_reached ();
4385     }
4386
4387   self->priv->transform_valid = FALSE;
4388
4389   clutter_actor_queue_redraw (self);
4390
4391   g_object_thaw_notify (obj);
4392 }
4393
4394 static void
4395 clutter_actor_set_property (GObject      *object,
4396                             guint         prop_id,
4397                             const GValue *value,
4398                             GParamSpec   *pspec)
4399 {
4400   ClutterActor *actor = CLUTTER_ACTOR (object);
4401   ClutterActorPrivate *priv = actor->priv;
4402
4403   switch (prop_id)
4404     {
4405     case PROP_X:
4406       clutter_actor_set_x (actor, g_value_get_float (value));
4407       break;
4408
4409     case PROP_Y:
4410       clutter_actor_set_y (actor, g_value_get_float (value));
4411       break;
4412
4413     case PROP_POSITION:
4414       {
4415         const ClutterPoint *pos = g_value_get_boxed (value);
4416
4417         if (pos != NULL)
4418           clutter_actor_set_position (actor, pos->x, pos->y);
4419         else
4420           clutter_actor_set_fixed_position_set (actor, FALSE);
4421       }
4422       break;
4423
4424     case PROP_WIDTH:
4425       clutter_actor_set_width (actor, g_value_get_float (value));
4426       break;
4427
4428     case PROP_HEIGHT:
4429       clutter_actor_set_height (actor, g_value_get_float (value));
4430       break;
4431
4432     case PROP_SIZE:
4433       {
4434         const ClutterSize *size = g_value_get_boxed (value);
4435
4436         if (size != NULL)
4437           clutter_actor_set_size (actor, size->width, size->height);
4438         else
4439           clutter_actor_set_size (actor, -1, -1);
4440       }
4441       break;
4442
4443     case PROP_FIXED_X:
4444       clutter_actor_set_x (actor, g_value_get_float (value));
4445       break;
4446
4447     case PROP_FIXED_Y:
4448       clutter_actor_set_y (actor, g_value_get_float (value));
4449       break;
4450
4451     case PROP_FIXED_POSITION_SET:
4452       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4453       break;
4454
4455     case PROP_MIN_WIDTH:
4456       clutter_actor_set_min_width (actor, g_value_get_float (value));
4457       break;
4458
4459     case PROP_MIN_HEIGHT:
4460       clutter_actor_set_min_height (actor, g_value_get_float (value));
4461       break;
4462
4463     case PROP_NATURAL_WIDTH:
4464       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4465       break;
4466
4467     case PROP_NATURAL_HEIGHT:
4468       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4469       break;
4470
4471     case PROP_MIN_WIDTH_SET:
4472       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4473       break;
4474
4475     case PROP_MIN_HEIGHT_SET:
4476       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4477       break;
4478
4479     case PROP_NATURAL_WIDTH_SET:
4480       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4481       break;
4482
4483     case PROP_NATURAL_HEIGHT_SET:
4484       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4485       break;
4486
4487     case PROP_REQUEST_MODE:
4488       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4489       break;
4490
4491     case PROP_DEPTH:
4492       clutter_actor_set_depth (actor, g_value_get_float (value));
4493       break;
4494
4495     case PROP_OPACITY:
4496       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4497       break;
4498
4499     case PROP_OFFSCREEN_REDIRECT:
4500       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4501       break;
4502
4503     case PROP_NAME:
4504       clutter_actor_set_name (actor, g_value_get_string (value));
4505       break;
4506
4507     case PROP_VISIBLE:
4508       if (g_value_get_boolean (value) == TRUE)
4509         clutter_actor_show (actor);
4510       else
4511         clutter_actor_hide (actor);
4512       break;
4513
4514     case PROP_SCALE_X:
4515       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4516                                       g_value_get_double (value));
4517       break;
4518
4519     case PROP_SCALE_Y:
4520       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4521                                       g_value_get_double (value));
4522       break;
4523
4524     case PROP_SCALE_CENTER_X:
4525       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4526                                       g_value_get_float (value));
4527       break;
4528
4529     case PROP_SCALE_CENTER_Y:
4530       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4531                                       g_value_get_float (value));
4532       break;
4533
4534     case PROP_SCALE_GRAVITY:
4535       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4536       break;
4537
4538     case PROP_CLIP:
4539       {
4540         const ClutterGeometry *geom = g_value_get_boxed (value);
4541
4542         clutter_actor_set_clip (actor,
4543                                 geom->x, geom->y,
4544                                 geom->width, geom->height);
4545       }
4546       break;
4547
4548     case PROP_CLIP_TO_ALLOCATION:
4549       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4550       break;
4551
4552     case PROP_REACTIVE:
4553       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4554       break;
4555
4556     case PROP_ROTATION_ANGLE_X:
4557       clutter_actor_set_rotation_angle (actor,
4558                                         CLUTTER_X_AXIS,
4559                                         g_value_get_double (value));
4560       break;
4561
4562     case PROP_ROTATION_ANGLE_Y:
4563       clutter_actor_set_rotation_angle (actor,
4564                                         CLUTTER_Y_AXIS,
4565                                         g_value_get_double (value));
4566       break;
4567
4568     case PROP_ROTATION_ANGLE_Z:
4569       clutter_actor_set_rotation_angle (actor,
4570                                         CLUTTER_Z_AXIS,
4571                                         g_value_get_double (value));
4572       break;
4573
4574     case PROP_ROTATION_CENTER_X:
4575       clutter_actor_set_rotation_center_internal (actor,
4576                                                   CLUTTER_X_AXIS,
4577                                                   g_value_get_boxed (value));
4578       break;
4579
4580     case PROP_ROTATION_CENTER_Y:
4581       clutter_actor_set_rotation_center_internal (actor,
4582                                                   CLUTTER_Y_AXIS,
4583                                                   g_value_get_boxed (value));
4584       break;
4585
4586     case PROP_ROTATION_CENTER_Z:
4587       clutter_actor_set_rotation_center_internal (actor,
4588                                                   CLUTTER_Z_AXIS,
4589                                                   g_value_get_boxed (value));
4590       break;
4591
4592     case PROP_ROTATION_CENTER_Z_GRAVITY:
4593       {
4594         const ClutterTransformInfo *info;
4595
4596         info = _clutter_actor_get_transform_info_or_defaults (actor);
4597         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4598                                                    g_value_get_enum (value));
4599       }
4600       break;
4601
4602     case PROP_ANCHOR_X:
4603       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4604                                       g_value_get_float (value));
4605       break;
4606
4607     case PROP_ANCHOR_Y:
4608       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4609                                       g_value_get_float (value));
4610       break;
4611
4612     case PROP_ANCHOR_GRAVITY:
4613       clutter_actor_set_anchor_point_from_gravity (actor,
4614                                                    g_value_get_enum (value));
4615       break;
4616
4617     case PROP_SHOW_ON_SET_PARENT:
4618       priv->show_on_set_parent = g_value_get_boolean (value);
4619       break;
4620
4621     case PROP_TEXT_DIRECTION:
4622       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4623       break;
4624
4625     case PROP_ACTIONS:
4626       clutter_actor_add_action (actor, g_value_get_object (value));
4627       break;
4628
4629     case PROP_CONSTRAINTS:
4630       clutter_actor_add_constraint (actor, g_value_get_object (value));
4631       break;
4632
4633     case PROP_EFFECT:
4634       clutter_actor_add_effect (actor, g_value_get_object (value));
4635       break;
4636
4637     case PROP_LAYOUT_MANAGER:
4638       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4639       break;
4640
4641     case PROP_X_EXPAND:
4642       clutter_actor_set_x_expand (actor, g_value_get_boolean (value));
4643       break;
4644
4645     case PROP_Y_EXPAND:
4646       clutter_actor_set_y_expand (actor, g_value_get_boolean (value));
4647       break;
4648
4649     case PROP_X_ALIGN:
4650       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4651       break;
4652
4653     case PROP_Y_ALIGN:
4654       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4655       break;
4656
4657     case PROP_MARGIN_TOP:
4658       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4659       break;
4660
4661     case PROP_MARGIN_BOTTOM:
4662       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4663       break;
4664
4665     case PROP_MARGIN_LEFT:
4666       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4667       break;
4668
4669     case PROP_MARGIN_RIGHT:
4670       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4671       break;
4672
4673     case PROP_BACKGROUND_COLOR:
4674       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4675       break;
4676
4677     case PROP_CONTENT:
4678       clutter_actor_set_content (actor, g_value_get_object (value));
4679       break;
4680
4681     case PROP_CONTENT_GRAVITY:
4682       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4683       break;
4684
4685     case PROP_MINIFICATION_FILTER:
4686       clutter_actor_set_content_scaling_filters (actor,
4687                                                  g_value_get_enum (value),
4688                                                  actor->priv->mag_filter);
4689       break;
4690
4691     case PROP_MAGNIFICATION_FILTER:
4692       clutter_actor_set_content_scaling_filters (actor,
4693                                                  actor->priv->min_filter,
4694                                                  g_value_get_enum (value));
4695       break;
4696
4697     default:
4698       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4699       break;
4700     }
4701 }
4702
4703 static void
4704 clutter_actor_get_property (GObject    *object,
4705                             guint       prop_id,
4706                             GValue     *value,
4707                             GParamSpec *pspec)
4708 {
4709   ClutterActor *actor = CLUTTER_ACTOR (object);
4710   ClutterActorPrivate *priv = actor->priv;
4711
4712   switch (prop_id)
4713     {
4714     case PROP_X:
4715       g_value_set_float (value, clutter_actor_get_x (actor));
4716       break;
4717
4718     case PROP_Y:
4719       g_value_set_float (value, clutter_actor_get_y (actor));
4720       break;
4721
4722     case PROP_POSITION:
4723       {
4724         ClutterPoint position;
4725
4726         clutter_point_init (&position,
4727                             clutter_actor_get_x (actor),
4728                             clutter_actor_get_y (actor));
4729         g_value_set_boxed (value, &position);
4730       }
4731       break;
4732
4733     case PROP_WIDTH:
4734       g_value_set_float (value, clutter_actor_get_width (actor));
4735       break;
4736
4737     case PROP_HEIGHT:
4738       g_value_set_float (value, clutter_actor_get_height (actor));
4739       break;
4740
4741     case PROP_SIZE:
4742       {
4743         ClutterSize size;
4744
4745         clutter_size_init (&size,
4746                            clutter_actor_get_width (actor),
4747                            clutter_actor_get_height (actor));
4748         g_value_set_boxed (value, &size);
4749       }
4750       break;
4751
4752     case PROP_FIXED_X:
4753       {
4754         const ClutterLayoutInfo *info;
4755
4756         info = _clutter_actor_get_layout_info_or_defaults (actor);
4757         g_value_set_float (value, info->fixed_pos.x);
4758       }
4759       break;
4760
4761     case PROP_FIXED_Y:
4762       {
4763         const ClutterLayoutInfo *info;
4764
4765         info = _clutter_actor_get_layout_info_or_defaults (actor);
4766         g_value_set_float (value, info->fixed_pos.y);
4767       }
4768       break;
4769
4770     case PROP_FIXED_POSITION_SET:
4771       g_value_set_boolean (value, priv->position_set);
4772       break;
4773
4774     case PROP_MIN_WIDTH:
4775       {
4776         const ClutterLayoutInfo *info;
4777
4778         info = _clutter_actor_get_layout_info_or_defaults (actor);
4779         g_value_set_float (value, info->minimum.width);
4780       }
4781       break;
4782
4783     case PROP_MIN_HEIGHT:
4784       {
4785         const ClutterLayoutInfo *info;
4786
4787         info = _clutter_actor_get_layout_info_or_defaults (actor);
4788         g_value_set_float (value, info->minimum.height);
4789       }
4790       break;
4791
4792     case PROP_NATURAL_WIDTH:
4793       {
4794         const ClutterLayoutInfo *info;
4795
4796         info = _clutter_actor_get_layout_info_or_defaults (actor);
4797         g_value_set_float (value, info->natural.width);
4798       }
4799       break;
4800
4801     case PROP_NATURAL_HEIGHT:
4802       {
4803         const ClutterLayoutInfo *info;
4804
4805         info = _clutter_actor_get_layout_info_or_defaults (actor);
4806         g_value_set_float (value, info->natural.height);
4807       }
4808       break;
4809
4810     case PROP_MIN_WIDTH_SET:
4811       g_value_set_boolean (value, priv->min_width_set);
4812       break;
4813
4814     case PROP_MIN_HEIGHT_SET:
4815       g_value_set_boolean (value, priv->min_height_set);
4816       break;
4817
4818     case PROP_NATURAL_WIDTH_SET:
4819       g_value_set_boolean (value, priv->natural_width_set);
4820       break;
4821
4822     case PROP_NATURAL_HEIGHT_SET:
4823       g_value_set_boolean (value, priv->natural_height_set);
4824       break;
4825
4826     case PROP_REQUEST_MODE:
4827       g_value_set_enum (value, priv->request_mode);
4828       break;
4829
4830     case PROP_ALLOCATION:
4831       g_value_set_boxed (value, &priv->allocation);
4832       break;
4833
4834     case PROP_DEPTH:
4835       g_value_set_float (value, clutter_actor_get_depth (actor));
4836       break;
4837
4838     case PROP_OPACITY:
4839       g_value_set_uint (value, priv->opacity);
4840       break;
4841
4842     case PROP_OFFSCREEN_REDIRECT:
4843       g_value_set_enum (value, priv->offscreen_redirect);
4844       break;
4845
4846     case PROP_NAME:
4847       g_value_set_string (value, priv->name);
4848       break;
4849
4850     case PROP_VISIBLE:
4851       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4852       break;
4853
4854     case PROP_MAPPED:
4855       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4856       break;
4857
4858     case PROP_REALIZED:
4859       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4860       break;
4861
4862     case PROP_HAS_CLIP:
4863       g_value_set_boolean (value, priv->has_clip);
4864       break;
4865
4866     case PROP_CLIP:
4867       {
4868         ClutterGeometry clip;
4869
4870         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4871         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4872         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4873         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4874
4875         g_value_set_boxed (value, &clip);
4876       }
4877       break;
4878
4879     case PROP_CLIP_TO_ALLOCATION:
4880       g_value_set_boolean (value, priv->clip_to_allocation);
4881       break;
4882
4883     case PROP_SCALE_X:
4884       {
4885         const ClutterTransformInfo *info;
4886
4887         info = _clutter_actor_get_transform_info_or_defaults (actor);
4888         g_value_set_double (value, info->scale_x);
4889       }
4890       break;
4891
4892     case PROP_SCALE_Y:
4893       {
4894         const ClutterTransformInfo *info;
4895
4896         info = _clutter_actor_get_transform_info_or_defaults (actor);
4897         g_value_set_double (value, info->scale_y);
4898       }
4899       break;
4900
4901     case PROP_SCALE_CENTER_X:
4902       {
4903         gfloat center;
4904
4905         clutter_actor_get_scale_center (actor, &center, NULL);
4906
4907         g_value_set_float (value, center);
4908       }
4909       break;
4910
4911     case PROP_SCALE_CENTER_Y:
4912       {
4913         gfloat center;
4914
4915         clutter_actor_get_scale_center (actor, NULL, &center);
4916
4917         g_value_set_float (value, center);
4918       }
4919       break;
4920
4921     case PROP_SCALE_GRAVITY:
4922       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4923       break;
4924
4925     case PROP_REACTIVE:
4926       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4927       break;
4928
4929     case PROP_ROTATION_ANGLE_X:
4930       {
4931         const ClutterTransformInfo *info;
4932
4933         info = _clutter_actor_get_transform_info_or_defaults (actor);
4934         g_value_set_double (value, info->rx_angle);
4935       }
4936       break;
4937
4938     case PROP_ROTATION_ANGLE_Y:
4939       {
4940         const ClutterTransformInfo *info;
4941
4942         info = _clutter_actor_get_transform_info_or_defaults (actor);
4943         g_value_set_double (value, info->ry_angle);
4944       }
4945       break;
4946
4947     case PROP_ROTATION_ANGLE_Z:
4948       {
4949         const ClutterTransformInfo *info;
4950
4951         info = _clutter_actor_get_transform_info_or_defaults (actor);
4952         g_value_set_double (value, info->rz_angle);
4953       }
4954       break;
4955
4956     case PROP_ROTATION_CENTER_X:
4957       {
4958         ClutterVertex center;
4959
4960         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4961                                     &center.x,
4962                                     &center.y,
4963                                     &center.z);
4964
4965         g_value_set_boxed (value, &center);
4966       }
4967       break;
4968
4969     case PROP_ROTATION_CENTER_Y:
4970       {
4971         ClutterVertex center;
4972
4973         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4974                                     &center.x,
4975                                     &center.y,
4976                                     &center.z);
4977
4978         g_value_set_boxed (value, &center);
4979       }
4980       break;
4981
4982     case PROP_ROTATION_CENTER_Z:
4983       {
4984         ClutterVertex center;
4985
4986         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4987                                     &center.x,
4988                                     &center.y,
4989                                     &center.z);
4990
4991         g_value_set_boxed (value, &center);
4992       }
4993       break;
4994
4995     case PROP_ROTATION_CENTER_Z_GRAVITY:
4996       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4997       break;
4998
4999     case PROP_ANCHOR_X:
5000       {
5001         const ClutterTransformInfo *info;
5002         gfloat anchor_x;
5003
5004         info = _clutter_actor_get_transform_info_or_defaults (actor);
5005         clutter_anchor_coord_get_units (actor, &info->anchor,
5006                                         &anchor_x,
5007                                         NULL,
5008                                         NULL);
5009         g_value_set_float (value, anchor_x);
5010       }
5011       break;
5012
5013     case PROP_ANCHOR_Y:
5014       {
5015         const ClutterTransformInfo *info;
5016         gfloat anchor_y;
5017
5018         info = _clutter_actor_get_transform_info_or_defaults (actor);
5019         clutter_anchor_coord_get_units (actor, &info->anchor,
5020                                         NULL,
5021                                         &anchor_y,
5022                                         NULL);
5023         g_value_set_float (value, anchor_y);
5024       }
5025       break;
5026
5027     case PROP_ANCHOR_GRAVITY:
5028       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
5029       break;
5030
5031     case PROP_SHOW_ON_SET_PARENT:
5032       g_value_set_boolean (value, priv->show_on_set_parent);
5033       break;
5034
5035     case PROP_TEXT_DIRECTION:
5036       g_value_set_enum (value, priv->text_direction);
5037       break;
5038
5039     case PROP_HAS_POINTER:
5040       g_value_set_boolean (value, priv->has_pointer);
5041       break;
5042
5043     case PROP_LAYOUT_MANAGER:
5044       g_value_set_object (value, priv->layout_manager);
5045       break;
5046
5047     case PROP_X_EXPAND:
5048       {
5049         const ClutterLayoutInfo *info;
5050
5051         info = _clutter_actor_get_layout_info_or_defaults (actor);
5052         g_value_set_boolean (value, info->x_expand);
5053       }
5054       break;
5055
5056     case PROP_Y_EXPAND:
5057       {
5058         const ClutterLayoutInfo *info;
5059
5060         info = _clutter_actor_get_layout_info_or_defaults (actor);
5061         g_value_set_boolean (value, info->y_expand);
5062       }
5063       break;
5064
5065     case PROP_X_ALIGN:
5066       {
5067         const ClutterLayoutInfo *info;
5068
5069         info = _clutter_actor_get_layout_info_or_defaults (actor);
5070         g_value_set_enum (value, info->x_align);
5071       }
5072       break;
5073
5074     case PROP_Y_ALIGN:
5075       {
5076         const ClutterLayoutInfo *info;
5077
5078         info = _clutter_actor_get_layout_info_or_defaults (actor);
5079         g_value_set_enum (value, info->y_align);
5080       }
5081       break;
5082
5083     case PROP_MARGIN_TOP:
5084       {
5085         const ClutterLayoutInfo *info;
5086
5087         info = _clutter_actor_get_layout_info_or_defaults (actor);
5088         g_value_set_float (value, info->margin.top);
5089       }
5090       break;
5091
5092     case PROP_MARGIN_BOTTOM:
5093       {
5094         const ClutterLayoutInfo *info;
5095
5096         info = _clutter_actor_get_layout_info_or_defaults (actor);
5097         g_value_set_float (value, info->margin.bottom);
5098       }
5099       break;
5100
5101     case PROP_MARGIN_LEFT:
5102       {
5103         const ClutterLayoutInfo *info;
5104
5105         info = _clutter_actor_get_layout_info_or_defaults (actor);
5106         g_value_set_float (value, info->margin.left);
5107       }
5108       break;
5109
5110     case PROP_MARGIN_RIGHT:
5111       {
5112         const ClutterLayoutInfo *info;
5113
5114         info = _clutter_actor_get_layout_info_or_defaults (actor);
5115         g_value_set_float (value, info->margin.right);
5116       }
5117       break;
5118
5119     case PROP_BACKGROUND_COLOR_SET:
5120       g_value_set_boolean (value, priv->bg_color_set);
5121       break;
5122
5123     case PROP_BACKGROUND_COLOR:
5124       g_value_set_boxed (value, &priv->bg_color);
5125       break;
5126
5127     case PROP_FIRST_CHILD:
5128       g_value_set_object (value, priv->first_child);
5129       break;
5130
5131     case PROP_LAST_CHILD:
5132       g_value_set_object (value, priv->last_child);
5133       break;
5134
5135     case PROP_CONTENT:
5136       g_value_set_object (value, priv->content);
5137       break;
5138
5139     case PROP_CONTENT_GRAVITY:
5140       g_value_set_enum (value, priv->content_gravity);
5141       break;
5142
5143     case PROP_CONTENT_BOX:
5144       {
5145         ClutterActorBox box = { 0, };
5146
5147         clutter_actor_get_content_box (actor, &box);
5148         g_value_set_boxed (value, &box);
5149       }
5150       break;
5151
5152     case PROP_MINIFICATION_FILTER:
5153       g_value_set_enum (value, priv->min_filter);
5154       break;
5155
5156     case PROP_MAGNIFICATION_FILTER:
5157       g_value_set_enum (value, priv->mag_filter);
5158       break;
5159
5160     default:
5161       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5162       break;
5163     }
5164 }
5165
5166 static void
5167 clutter_actor_dispose (GObject *object)
5168 {
5169   ClutterActor *self = CLUTTER_ACTOR (object);
5170   ClutterActorPrivate *priv = self->priv;
5171
5172   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5173                 priv->id,
5174                 g_type_name (G_OBJECT_TYPE (self)),
5175                 object->ref_count);
5176
5177   g_signal_emit (self, actor_signals[DESTROY], 0);
5178
5179   /* avoid recursing when called from clutter_actor_destroy() */
5180   if (priv->parent != NULL)
5181     {
5182       ClutterActor *parent = priv->parent;
5183
5184       /* go through the Container implementation unless this
5185        * is an internal child and has been marked as such.
5186        *
5187        * removing the actor from its parent will reset the
5188        * realized and mapped states.
5189        */
5190       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5191         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5192       else
5193         clutter_actor_remove_child_internal (parent, self,
5194                                              REMOVE_CHILD_LEGACY_FLAGS);
5195     }
5196
5197   /* parent must be gone at this point */
5198   g_assert (priv->parent == NULL);
5199
5200   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5201     {
5202       /* can't be mapped or realized with no parent */
5203       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5204       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5205     }
5206
5207   g_clear_object (&priv->pango_context);
5208   g_clear_object (&priv->actions);
5209   g_clear_object (&priv->constraints);
5210   g_clear_object (&priv->effects);
5211   g_clear_object (&priv->flatten_effect);
5212
5213   if (priv->layout_manager != NULL)
5214     {
5215       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5216       g_clear_object (&priv->layout_manager);
5217     }
5218
5219   if (priv->content != NULL)
5220     {
5221       _clutter_content_detached (priv->content, self);
5222       g_clear_object (&priv->content);
5223     }
5224
5225   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5226 }
5227
5228 static void
5229 clutter_actor_finalize (GObject *object)
5230 {
5231   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5232
5233   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5234                 priv->name != NULL ? priv->name : "<none>",
5235                 priv->id,
5236                 g_type_name (G_OBJECT_TYPE (object)));
5237
5238   _clutter_context_release_id (priv->id);
5239
5240   g_free (priv->name);
5241
5242   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5243 }
5244
5245
5246 /**
5247  * clutter_actor_get_accessible:
5248  * @self: a #ClutterActor
5249  *
5250  * Returns the accessible object that describes the actor to an
5251  * assistive technology.
5252  *
5253  * If no class-specific #AtkObject implementation is available for the
5254  * actor instance in question, it will inherit an #AtkObject
5255  * implementation from the first ancestor class for which such an
5256  * implementation is defined.
5257  *
5258  * The documentation of the <ulink
5259  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5260  * library contains more information about accessible objects and
5261  * their uses.
5262  *
5263  * Returns: (transfer none): the #AtkObject associated with @actor
5264  */
5265 AtkObject *
5266 clutter_actor_get_accessible (ClutterActor *self)
5267 {
5268   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5269
5270   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5271 }
5272
5273 static AtkObject *
5274 clutter_actor_real_get_accessible (ClutterActor *actor)
5275 {
5276   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5277 }
5278
5279 static AtkObject *
5280 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5281 {
5282   AtkObject *accessible;
5283
5284   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5285   if (accessible != NULL)
5286     g_object_ref (accessible);
5287
5288   return accessible;
5289 }
5290
5291 static void
5292 atk_implementor_iface_init (AtkImplementorIface *iface)
5293 {
5294   iface->ref_accessible = _clutter_actor_ref_accessible;
5295 }
5296
5297 static gboolean
5298 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5299                                            ClutterPaintVolume *volume)
5300 {
5301   ClutterActorPrivate *priv = self->priv;
5302   gboolean res = TRUE;
5303
5304   /* we start from the allocation */
5305   clutter_paint_volume_set_width (volume,
5306                                   priv->allocation.x2 - priv->allocation.x1);
5307   clutter_paint_volume_set_height (volume,
5308                                    priv->allocation.y2 - priv->allocation.y1);
5309
5310   /* if the actor has a clip set then we have a pretty definite
5311    * size for the paint volume: the actor cannot possibly paint
5312    * outside the clip region.
5313    */
5314   if (priv->clip_to_allocation)
5315     {
5316       /* the allocation has already been set, so we just flip the
5317        * return value
5318        */
5319       res = TRUE;
5320     }
5321   else
5322     {
5323       ClutterActor *child;
5324
5325       if (priv->has_clip &&
5326           priv->clip.width >= 0 &&
5327           priv->clip.height >= 0)
5328         {
5329           ClutterVertex origin;
5330
5331           origin.x = priv->clip.x;
5332           origin.y = priv->clip.y;
5333           origin.z = 0;
5334
5335           clutter_paint_volume_set_origin (volume, &origin);
5336           clutter_paint_volume_set_width (volume, priv->clip.width);
5337           clutter_paint_volume_set_height (volume, priv->clip.height);
5338
5339           res = TRUE;
5340         }
5341
5342       /* if we don't have children we just bail out here... */
5343       if (priv->n_children == 0)
5344         return res;
5345
5346       /* ...but if we have children then we ask for their paint volume in
5347        * our coordinates. if any of our children replies that it doesn't
5348        * have a paint volume, we bail out
5349        */
5350       for (child = priv->first_child;
5351            child != NULL;
5352            child = child->priv->next_sibling)
5353         {
5354           const ClutterPaintVolume *child_volume;
5355
5356           if (!CLUTTER_ACTOR_IS_MAPPED (child))
5357             continue;
5358
5359           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5360           if (child_volume == NULL)
5361             {
5362               res = FALSE;
5363               break;
5364             }
5365
5366           clutter_paint_volume_union (volume, child_volume);
5367           res = TRUE;
5368         }
5369     }
5370
5371   return res;
5372
5373 }
5374
5375 static gboolean
5376 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5377                                      ClutterPaintVolume *volume)
5378 {
5379   ClutterActorClass *klass;
5380   gboolean res;
5381
5382   klass = CLUTTER_ACTOR_GET_CLASS (self);
5383
5384   /* XXX - this thoroughly sucks, but we don't want to penalize users
5385    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5386    * redraw. This should go away in 2.0.
5387    */
5388   if (klass->paint == clutter_actor_real_paint &&
5389       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5390     {
5391       res = TRUE;
5392     }
5393   else
5394     {
5395       /* this is the default return value: we cannot know if a class
5396        * is going to paint outside its allocation, so we take the
5397        * conservative approach.
5398        */
5399       res = FALSE;
5400     }
5401
5402   /* update_default_paint_volume() should only fail if one of the children
5403    * reported an invalid, or no, paint volume
5404    */
5405   if (!clutter_actor_update_default_paint_volume (self, volume))
5406     return FALSE;
5407
5408   return res;
5409 }
5410
5411 /**
5412  * clutter_actor_get_default_paint_volume:
5413  * @self: a #ClutterActor
5414  *
5415  * Retrieves the default paint volume for @self.
5416  *
5417  * This function provides the same #ClutterPaintVolume that would be
5418  * computed by the default implementation inside #ClutterActor of the
5419  * #ClutterActorClass.get_paint_volume() virtual function.
5420  *
5421  * This function should only be used by #ClutterActor subclasses that
5422  * cannot chain up to the parent implementation when computing their
5423  * paint volume.
5424  *
5425  * Return value: (transfer none): a pointer to the default
5426  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5427  *   the actor could not compute a valid paint volume. The returned value
5428  *   is not guaranteed to be stable across multiple frames, so if you
5429  *   want to retain it, you will need to copy it using
5430  *   clutter_paint_volume_copy().
5431  *
5432  * Since: 1.10
5433  */
5434 const ClutterPaintVolume *
5435 clutter_actor_get_default_paint_volume (ClutterActor *self)
5436 {
5437   ClutterPaintVolume volume;
5438   ClutterPaintVolume *res;
5439
5440   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5441
5442   res = NULL;
5443   _clutter_paint_volume_init_static (&volume, self);
5444   if (clutter_actor_update_default_paint_volume (self, &volume))
5445     {
5446       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5447
5448       if (stage != NULL)
5449         {
5450           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5451           _clutter_paint_volume_copy_static (&volume, res);
5452         }
5453     }
5454
5455   clutter_paint_volume_free (&volume);
5456
5457   return res;
5458 }
5459
5460 static gboolean
5461 clutter_actor_real_has_overlaps (ClutterActor *self)
5462 {
5463   /* By default we'll assume that all actors need an offscreen redirect to get
5464    * the correct opacity. Actors such as ClutterTexture that would never need
5465    * an offscreen redirect can override this to return FALSE. */
5466   return TRUE;
5467 }
5468
5469 static void
5470 clutter_actor_real_destroy (ClutterActor *actor)
5471 {
5472   ClutterActorIter iter;
5473
5474   g_object_freeze_notify (G_OBJECT (actor));
5475
5476   clutter_actor_iter_init (&iter, actor);
5477   while (clutter_actor_iter_next (&iter, NULL))
5478     clutter_actor_iter_destroy (&iter);
5479
5480   g_object_thaw_notify (G_OBJECT (actor));
5481 }
5482
5483 static GObject *
5484 clutter_actor_constructor (GType gtype,
5485                            guint n_props,
5486                            GObjectConstructParam *props)
5487 {
5488   GObjectClass *gobject_class;
5489   ClutterActor *self;
5490   GObject *retval;
5491
5492   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5493   retval = gobject_class->constructor (gtype, n_props, props);
5494   self = CLUTTER_ACTOR (retval);
5495
5496   if (self->priv->layout_manager == NULL)
5497     {
5498       ClutterLayoutManager *default_layout;
5499
5500       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5501
5502       default_layout = clutter_fixed_layout_new ();
5503       clutter_actor_set_layout_manager (self, default_layout);
5504     }
5505
5506   return retval;
5507 }
5508
5509 static void
5510 clutter_actor_class_init (ClutterActorClass *klass)
5511 {
5512   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5513
5514   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5515   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5516   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5517   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5518
5519   object_class->constructor = clutter_actor_constructor;
5520   object_class->set_property = clutter_actor_set_property;
5521   object_class->get_property = clutter_actor_get_property;
5522   object_class->dispose = clutter_actor_dispose;
5523   object_class->finalize = clutter_actor_finalize;
5524
5525   klass->show = clutter_actor_real_show;
5526   klass->show_all = clutter_actor_show;
5527   klass->hide = clutter_actor_real_hide;
5528   klass->hide_all = clutter_actor_hide;
5529   klass->map = clutter_actor_real_map;
5530   klass->unmap = clutter_actor_real_unmap;
5531   klass->unrealize = clutter_actor_real_unrealize;
5532   klass->pick = clutter_actor_real_pick;
5533   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5534   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5535   klass->allocate = clutter_actor_real_allocate;
5536   klass->queue_redraw = clutter_actor_real_queue_redraw;
5537   klass->queue_relayout = clutter_actor_real_queue_relayout;
5538   klass->apply_transform = clutter_actor_real_apply_transform;
5539   klass->get_accessible = clutter_actor_real_get_accessible;
5540   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5541   klass->has_overlaps = clutter_actor_real_has_overlaps;
5542   klass->paint = clutter_actor_real_paint;
5543   klass->destroy = clutter_actor_real_destroy;
5544
5545   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5546
5547   /**
5548    * ClutterActor:x:
5549    *
5550    * X coordinate of the actor in pixels. If written, forces a fixed
5551    * position for the actor. If read, returns the fixed position if any,
5552    * otherwise the allocation if available, otherwise 0.
5553    *
5554    * The #ClutterActor:x property is animatable.
5555    */
5556   obj_props[PROP_X] =
5557     g_param_spec_float ("x",
5558                         P_("X coordinate"),
5559                         P_("X coordinate of the actor"),
5560                         -G_MAXFLOAT, G_MAXFLOAT,
5561                         0.0,
5562                         G_PARAM_READWRITE |
5563                         G_PARAM_STATIC_STRINGS |
5564                         CLUTTER_PARAM_ANIMATABLE);
5565
5566   /**
5567    * ClutterActor:y:
5568    *
5569    * Y coordinate of the actor in pixels. If written, forces a fixed
5570    * position for the actor.  If read, returns the fixed position if
5571    * any, otherwise the allocation if available, otherwise 0.
5572    *
5573    * The #ClutterActor:y property is animatable.
5574    */
5575   obj_props[PROP_Y] =
5576     g_param_spec_float ("y",
5577                         P_("Y coordinate"),
5578                         P_("Y coordinate of the actor"),
5579                         -G_MAXFLOAT, G_MAXFLOAT,
5580                         0.0,
5581                         G_PARAM_READWRITE |
5582                         G_PARAM_STATIC_STRINGS |
5583                         CLUTTER_PARAM_ANIMATABLE);
5584
5585   /**
5586    * ClutterActor:position:
5587    *
5588    * The position of the origin of the actor.
5589    *
5590    * This property is a shorthand for setting and getting the
5591    * #ClutterActor:x and #ClutterActor:y properties at the same
5592    * time.
5593    *
5594    * The #ClutterActor:position property is animatable.
5595    *
5596    * Since: 1.12
5597    */
5598   obj_props[PROP_POSITION] =
5599     g_param_spec_boxed ("position",
5600                         P_("Position"),
5601                         P_("The position of the origin of the actor"),
5602                         CLUTTER_TYPE_POINT,
5603                         G_PARAM_READWRITE |
5604                         G_PARAM_STATIC_STRINGS |
5605                         CLUTTER_PARAM_ANIMATABLE);
5606
5607   /**
5608    * ClutterActor:width:
5609    *
5610    * Width of the actor (in pixels). If written, forces the minimum and
5611    * natural size request of the actor to the given width. If read, returns
5612    * the allocated width if available, otherwise the width request.
5613    *
5614    * The #ClutterActor:width property is animatable.
5615    */
5616   obj_props[PROP_WIDTH] =
5617     g_param_spec_float ("width",
5618                         P_("Width"),
5619                         P_("Width of the actor"),
5620                         0.0, G_MAXFLOAT,
5621                         0.0,
5622                         G_PARAM_READWRITE |
5623                         G_PARAM_STATIC_STRINGS |
5624                         CLUTTER_PARAM_ANIMATABLE);
5625
5626   /**
5627    * ClutterActor:height:
5628    *
5629    * Height of the actor (in pixels).  If written, forces the minimum and
5630    * natural size request of the actor to the given height. If read, returns
5631    * the allocated height if available, otherwise the height request.
5632    *
5633    * The #ClutterActor:height property is animatable.
5634    */
5635   obj_props[PROP_HEIGHT] =
5636     g_param_spec_float ("height",
5637                         P_("Height"),
5638                         P_("Height of the actor"),
5639                         0.0, G_MAXFLOAT,
5640                         0.0,
5641                         G_PARAM_READWRITE |
5642                         G_PARAM_STATIC_STRINGS |
5643                         CLUTTER_PARAM_ANIMATABLE);
5644
5645   /**
5646    * ClutterActor:size:
5647    *
5648    * The size of the actor.
5649    *
5650    * This property is a shorthand for setting and getting the
5651    * #ClutterActor:width and #ClutterActor:height at the same time.
5652    *
5653    * The #ClutterActor:size property is animatable.
5654    *
5655    * Since: 1.12
5656    */
5657   obj_props[PROP_SIZE] =
5658     g_param_spec_boxed ("size",
5659                         P_("Size"),
5660                         P_("The size of the actor"),
5661                         CLUTTER_TYPE_SIZE,
5662                         G_PARAM_READWRITE |
5663                         G_PARAM_STATIC_STRINGS |
5664                         CLUTTER_PARAM_ANIMATABLE);
5665
5666   /**
5667    * ClutterActor:fixed-x:
5668    *
5669    * The fixed X position of the actor in pixels.
5670    *
5671    * Writing this property sets #ClutterActor:fixed-position-set
5672    * property as well, as a side effect
5673    *
5674    * Since: 0.8
5675    */
5676   obj_props[PROP_FIXED_X] =
5677     g_param_spec_float ("fixed-x",
5678                         P_("Fixed X"),
5679                         P_("Forced X position of the actor"),
5680                         -G_MAXFLOAT, G_MAXFLOAT,
5681                         0.0,
5682                         CLUTTER_PARAM_READWRITE);
5683
5684   /**
5685    * ClutterActor:fixed-y:
5686    *
5687    * The fixed Y position of the actor in pixels.
5688    *
5689    * Writing this property sets the #ClutterActor:fixed-position-set
5690    * property as well, as a side effect
5691    *
5692    * Since: 0.8
5693    */
5694   obj_props[PROP_FIXED_Y] =
5695     g_param_spec_float ("fixed-y",
5696                         P_("Fixed Y"),
5697                         P_("Forced Y position of the actor"),
5698                         -G_MAXFLOAT, G_MAXFLOAT,
5699                         0,
5700                         CLUTTER_PARAM_READWRITE);
5701
5702   /**
5703    * ClutterActor:fixed-position-set:
5704    *
5705    * This flag controls whether the #ClutterActor:fixed-x and
5706    * #ClutterActor:fixed-y properties are used
5707    *
5708    * Since: 0.8
5709    */
5710   obj_props[PROP_FIXED_POSITION_SET] =
5711     g_param_spec_boolean ("fixed-position-set",
5712                           P_("Fixed position set"),
5713                           P_("Whether to use fixed positioning for the actor"),
5714                           FALSE,
5715                           CLUTTER_PARAM_READWRITE);
5716
5717   /**
5718    * ClutterActor:min-width:
5719    *
5720    * A forced minimum width request for the actor, in pixels
5721    *
5722    * Writing this property sets the #ClutterActor:min-width-set property
5723    * as well, as a side effect.
5724    *
5725    *This property overrides the usual width request of the actor.
5726    *
5727    * Since: 0.8
5728    */
5729   obj_props[PROP_MIN_WIDTH] =
5730     g_param_spec_float ("min-width",
5731                         P_("Min Width"),
5732                         P_("Forced minimum width request for the actor"),
5733                         0.0, G_MAXFLOAT,
5734                         0.0,
5735                         CLUTTER_PARAM_READWRITE);
5736
5737   /**
5738    * ClutterActor:min-height:
5739    *
5740    * A forced minimum height request for the actor, in pixels
5741    *
5742    * Writing this property sets the #ClutterActor:min-height-set property
5743    * as well, as a side effect. This property overrides the usual height
5744    * request of the actor.
5745    *
5746    * Since: 0.8
5747    */
5748   obj_props[PROP_MIN_HEIGHT] =
5749     g_param_spec_float ("min-height",
5750                         P_("Min Height"),
5751                         P_("Forced minimum height request for the actor"),
5752                         0.0, G_MAXFLOAT,
5753                         0.0,
5754                         CLUTTER_PARAM_READWRITE);
5755
5756   /**
5757    * ClutterActor:natural-width:
5758    *
5759    * A forced natural width request for the actor, in pixels
5760    *
5761    * Writing this property sets the #ClutterActor:natural-width-set
5762    * property as well, as a side effect. This property overrides the
5763    * usual width request of the actor
5764    *
5765    * Since: 0.8
5766    */
5767   obj_props[PROP_NATURAL_WIDTH] =
5768     g_param_spec_float ("natural-width",
5769                         P_("Natural Width"),
5770                         P_("Forced natural width request for the actor"),
5771                         0.0, G_MAXFLOAT,
5772                         0.0,
5773                         CLUTTER_PARAM_READWRITE);
5774
5775   /**
5776    * ClutterActor:natural-height:
5777    *
5778    * A forced natural height request for the actor, in pixels
5779    *
5780    * Writing this property sets the #ClutterActor:natural-height-set
5781    * property as well, as a side effect. This property overrides the
5782    * usual height request of the actor
5783    *
5784    * Since: 0.8
5785    */
5786   obj_props[PROP_NATURAL_HEIGHT] =
5787     g_param_spec_float ("natural-height",
5788                         P_("Natural Height"),
5789                         P_("Forced natural height request for the actor"),
5790                         0.0, G_MAXFLOAT,
5791                         0.0,
5792                         CLUTTER_PARAM_READWRITE);
5793
5794   /**
5795    * ClutterActor:min-width-set:
5796    *
5797    * This flag controls whether the #ClutterActor:min-width property
5798    * is used
5799    *
5800    * Since: 0.8
5801    */
5802   obj_props[PROP_MIN_WIDTH_SET] =
5803     g_param_spec_boolean ("min-width-set",
5804                           P_("Minimum width set"),
5805                           P_("Whether to use the min-width property"),
5806                           FALSE,
5807                           CLUTTER_PARAM_READWRITE);
5808
5809   /**
5810    * ClutterActor:min-height-set:
5811    *
5812    * This flag controls whether the #ClutterActor:min-height property
5813    * is used
5814    *
5815    * Since: 0.8
5816    */
5817   obj_props[PROP_MIN_HEIGHT_SET] =
5818     g_param_spec_boolean ("min-height-set",
5819                           P_("Minimum height set"),
5820                           P_("Whether to use the min-height property"),
5821                           FALSE,
5822                           CLUTTER_PARAM_READWRITE);
5823
5824   /**
5825    * ClutterActor:natural-width-set:
5826    *
5827    * This flag controls whether the #ClutterActor:natural-width property
5828    * is used
5829    *
5830    * Since: 0.8
5831    */
5832   obj_props[PROP_NATURAL_WIDTH_SET] =
5833     g_param_spec_boolean ("natural-width-set",
5834                           P_("Natural width set"),
5835                           P_("Whether to use the natural-width property"),
5836                           FALSE,
5837                           CLUTTER_PARAM_READWRITE);
5838
5839   /**
5840    * ClutterActor:natural-height-set:
5841    *
5842    * This flag controls whether the #ClutterActor:natural-height property
5843    * is used
5844    *
5845    * Since: 0.8
5846    */
5847   obj_props[PROP_NATURAL_HEIGHT_SET] =
5848     g_param_spec_boolean ("natural-height-set",
5849                           P_("Natural height set"),
5850                           P_("Whether to use the natural-height property"),
5851                           FALSE,
5852                           CLUTTER_PARAM_READWRITE);
5853
5854   /**
5855    * ClutterActor:allocation:
5856    *
5857    * The allocation for the actor, in pixels
5858    *
5859    * This is property is read-only, but you might monitor it to know when an
5860    * actor moves or resizes
5861    *
5862    * Since: 0.8
5863    */
5864   obj_props[PROP_ALLOCATION] =
5865     g_param_spec_boxed ("allocation",
5866                         P_("Allocation"),
5867                         P_("The actor's allocation"),
5868                         CLUTTER_TYPE_ACTOR_BOX,
5869                         G_PARAM_READABLE |
5870                         G_PARAM_STATIC_STRINGS |
5871                         CLUTTER_PARAM_ANIMATABLE);
5872
5873   /**
5874    * ClutterActor:request-mode:
5875    *
5876    * Request mode for the #ClutterActor. The request mode determines the
5877    * type of geometry management used by the actor, either height for width
5878    * (the default) or width for height.
5879    *
5880    * For actors implementing height for width, the parent container should get
5881    * the preferred width first, and then the preferred height for that width.
5882    *
5883    * For actors implementing width for height, the parent container should get
5884    * the preferred height first, and then the preferred width for that height.
5885    *
5886    * For instance:
5887    *
5888    * |[
5889    *   ClutterRequestMode mode;
5890    *   gfloat natural_width, min_width;
5891    *   gfloat natural_height, min_height;
5892    *
5893    *   mode = clutter_actor_get_request_mode (child);
5894    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5895    *     {
5896    *       clutter_actor_get_preferred_width (child, -1,
5897    *                                          &amp;min_width,
5898    *                                          &amp;natural_width);
5899    *       clutter_actor_get_preferred_height (child, natural_width,
5900    *                                           &amp;min_height,
5901    *                                           &amp;natural_height);
5902    *     }
5903    *   else
5904    *     {
5905    *       clutter_actor_get_preferred_height (child, -1,
5906    *                                           &amp;min_height,
5907    *                                           &amp;natural_height);
5908    *       clutter_actor_get_preferred_width (child, natural_height,
5909    *                                          &amp;min_width,
5910    *                                          &amp;natural_width);
5911    *     }
5912    * ]|
5913    *
5914    * will retrieve the minimum and natural width and height depending on the
5915    * preferred request mode of the #ClutterActor "child".
5916    *
5917    * The clutter_actor_get_preferred_size() function will implement this
5918    * check for you.
5919    *
5920    * Since: 0.8
5921    */
5922   obj_props[PROP_REQUEST_MODE] =
5923     g_param_spec_enum ("request-mode",
5924                        P_("Request Mode"),
5925                        P_("The actor's request mode"),
5926                        CLUTTER_TYPE_REQUEST_MODE,
5927                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5928                        CLUTTER_PARAM_READWRITE);
5929
5930   /**
5931    * ClutterActor:depth:
5932    *
5933    * The position of the actor on the Z axis.
5934    *
5935    * The #ClutterActor:depth property is relative to the parent's
5936    * modelview matrix.
5937    *
5938    * The #ClutterActor:depth property is animatable.
5939    *
5940    * Since: 0.6
5941    */
5942   obj_props[PROP_DEPTH] =
5943     g_param_spec_float ("depth",
5944                         P_("Depth"),
5945                         P_("Position on the Z axis"),
5946                         -G_MAXFLOAT, G_MAXFLOAT,
5947                         0.0,
5948                         G_PARAM_READWRITE |
5949                         G_PARAM_STATIC_STRINGS |
5950                         CLUTTER_PARAM_ANIMATABLE);
5951
5952   /**
5953    * ClutterActor:opacity:
5954    *
5955    * Opacity of an actor, between 0 (fully transparent) and
5956    * 255 (fully opaque)
5957    *
5958    * The #ClutterActor:opacity property is animatable.
5959    */
5960   obj_props[PROP_OPACITY] =
5961     g_param_spec_uint ("opacity",
5962                        P_("Opacity"),
5963                        P_("Opacity of an actor"),
5964                        0, 255,
5965                        255,
5966                        G_PARAM_READWRITE |
5967                        G_PARAM_STATIC_STRINGS |
5968                        CLUTTER_PARAM_ANIMATABLE);
5969
5970   /**
5971    * ClutterActor:offscreen-redirect:
5972    *
5973    * Determines the conditions in which the actor will be redirected
5974    * to an offscreen framebuffer while being painted. For example this
5975    * can be used to cache an actor in a framebuffer or for improved
5976    * handling of transparent actors. See
5977    * clutter_actor_set_offscreen_redirect() for details.
5978    *
5979    * Since: 1.8
5980    */
5981   obj_props[PROP_OFFSCREEN_REDIRECT] =
5982     g_param_spec_flags ("offscreen-redirect",
5983                         P_("Offscreen redirect"),
5984                         P_("Flags controlling when to flatten the actor into a single image"),
5985                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5986                         0,
5987                         CLUTTER_PARAM_READWRITE);
5988
5989   /**
5990    * ClutterActor:visible:
5991    *
5992    * Whether the actor is set to be visible or not
5993    *
5994    * See also #ClutterActor:mapped
5995    */
5996   obj_props[PROP_VISIBLE] =
5997     g_param_spec_boolean ("visible",
5998                           P_("Visible"),
5999                           P_("Whether the actor is visible or not"),
6000                           FALSE,
6001                           CLUTTER_PARAM_READWRITE);
6002
6003   /**
6004    * ClutterActor:mapped:
6005    *
6006    * Whether the actor is mapped (will be painted when the stage
6007    * to which it belongs is mapped)
6008    *
6009    * Since: 1.0
6010    */
6011   obj_props[PROP_MAPPED] =
6012     g_param_spec_boolean ("mapped",
6013                           P_("Mapped"),
6014                           P_("Whether the actor will be painted"),
6015                           FALSE,
6016                           CLUTTER_PARAM_READABLE);
6017
6018   /**
6019    * ClutterActor:realized:
6020    *
6021    * Whether the actor has been realized
6022    *
6023    * Since: 1.0
6024    */
6025   obj_props[PROP_REALIZED] =
6026     g_param_spec_boolean ("realized",
6027                           P_("Realized"),
6028                           P_("Whether the actor has been realized"),
6029                           FALSE,
6030                           CLUTTER_PARAM_READABLE);
6031
6032   /**
6033    * ClutterActor:reactive:
6034    *
6035    * Whether the actor is reactive to events or not
6036    *
6037    * Only reactive actors will emit event-related signals
6038    *
6039    * Since: 0.6
6040    */
6041   obj_props[PROP_REACTIVE] =
6042     g_param_spec_boolean ("reactive",
6043                           P_("Reactive"),
6044                           P_("Whether the actor is reactive to events"),
6045                           FALSE,
6046                           CLUTTER_PARAM_READWRITE);
6047
6048   /**
6049    * ClutterActor:has-clip:
6050    *
6051    * Whether the actor has the #ClutterActor:clip property set or not
6052    */
6053   obj_props[PROP_HAS_CLIP] =
6054     g_param_spec_boolean ("has-clip",
6055                           P_("Has Clip"),
6056                           P_("Whether the actor has a clip set"),
6057                           FALSE,
6058                           CLUTTER_PARAM_READABLE);
6059
6060   /**
6061    * ClutterActor:clip:
6062    *
6063    * The clip region for the actor, in actor-relative coordinates
6064    *
6065    * Every part of the actor outside the clip region will not be
6066    * painted
6067    */
6068   obj_props[PROP_CLIP] =
6069     g_param_spec_boxed ("clip",
6070                         P_("Clip"),
6071                         P_("The clip region for the actor"),
6072                         CLUTTER_TYPE_GEOMETRY,
6073                         CLUTTER_PARAM_READWRITE);
6074
6075   /**
6076    * ClutterActor:name:
6077    *
6078    * The name of the actor
6079    *
6080    * Since: 0.2
6081    */
6082   obj_props[PROP_NAME] =
6083     g_param_spec_string ("name",
6084                          P_("Name"),
6085                          P_("Name of the actor"),
6086                          NULL,
6087                          CLUTTER_PARAM_READWRITE);
6088
6089   /**
6090    * ClutterActor:scale-x:
6091    *
6092    * The horizontal scale of the actor.
6093    *
6094    * The #ClutterActor:scale-x property is animatable.
6095    *
6096    * Since: 0.6
6097    */
6098   obj_props[PROP_SCALE_X] =
6099     g_param_spec_double ("scale-x",
6100                          P_("Scale X"),
6101                          P_("Scale factor on the X axis"),
6102                          0.0, G_MAXDOUBLE,
6103                          1.0,
6104                          G_PARAM_READWRITE |
6105                          G_PARAM_STATIC_STRINGS |
6106                          CLUTTER_PARAM_ANIMATABLE);
6107
6108   /**
6109    * ClutterActor:scale-y:
6110    *
6111    * The vertical scale of the actor.
6112    *
6113    * The #ClutterActor:scale-y property is animatable.
6114    *
6115    * Since: 0.6
6116    */
6117   obj_props[PROP_SCALE_Y] =
6118     g_param_spec_double ("scale-y",
6119                          P_("Scale Y"),
6120                          P_("Scale factor on the Y axis"),
6121                          0.0, G_MAXDOUBLE,
6122                          1.0,
6123                          G_PARAM_READWRITE |
6124                          G_PARAM_STATIC_STRINGS |
6125                          CLUTTER_PARAM_ANIMATABLE);
6126
6127   /**
6128    * ClutterActor:scale-center-x:
6129    *
6130    * The horizontal center point for scaling
6131    *
6132    * Since: 1.0
6133    */
6134   obj_props[PROP_SCALE_CENTER_X] =
6135     g_param_spec_float ("scale-center-x",
6136                         P_("Scale Center X"),
6137                         P_("Horizontal scale center"),
6138                         -G_MAXFLOAT, G_MAXFLOAT,
6139                         0.0,
6140                         CLUTTER_PARAM_READWRITE);
6141
6142   /**
6143    * ClutterActor:scale-center-y:
6144    *
6145    * The vertical center point for scaling
6146    *
6147    * Since: 1.0
6148    */
6149   obj_props[PROP_SCALE_CENTER_Y] =
6150     g_param_spec_float ("scale-center-y",
6151                         P_("Scale Center Y"),
6152                         P_("Vertical scale center"),
6153                         -G_MAXFLOAT, G_MAXFLOAT,
6154                         0.0,
6155                         CLUTTER_PARAM_READWRITE);
6156
6157   /**
6158    * ClutterActor:scale-gravity:
6159    *
6160    * The center point for scaling expressed as a #ClutterGravity
6161    *
6162    * Since: 1.0
6163    */
6164   obj_props[PROP_SCALE_GRAVITY] =
6165     g_param_spec_enum ("scale-gravity",
6166                        P_("Scale Gravity"),
6167                        P_("The center of scaling"),
6168                        CLUTTER_TYPE_GRAVITY,
6169                        CLUTTER_GRAVITY_NONE,
6170                        CLUTTER_PARAM_READWRITE);
6171
6172   /**
6173    * ClutterActor:rotation-angle-x:
6174    *
6175    * The rotation angle on the X axis.
6176    *
6177    * The #ClutterActor:rotation-angle-x property is animatable.
6178    *
6179    * Since: 0.6
6180    */
6181   obj_props[PROP_ROTATION_ANGLE_X] =
6182     g_param_spec_double ("rotation-angle-x",
6183                          P_("Rotation Angle X"),
6184                          P_("The rotation angle on the X axis"),
6185                          -G_MAXDOUBLE, G_MAXDOUBLE,
6186                          0.0,
6187                          G_PARAM_READWRITE |
6188                          G_PARAM_STATIC_STRINGS |
6189                          CLUTTER_PARAM_ANIMATABLE);
6190
6191   /**
6192    * ClutterActor:rotation-angle-y:
6193    *
6194    * The rotation angle on the Y axis
6195    *
6196    * The #ClutterActor:rotation-angle-y property is animatable.
6197    *
6198    * Since: 0.6
6199    */
6200   obj_props[PROP_ROTATION_ANGLE_Y] =
6201     g_param_spec_double ("rotation-angle-y",
6202                          P_("Rotation Angle Y"),
6203                          P_("The rotation angle on the Y axis"),
6204                          -G_MAXDOUBLE, G_MAXDOUBLE,
6205                          0.0,
6206                          G_PARAM_READWRITE |
6207                          G_PARAM_STATIC_STRINGS |
6208                          CLUTTER_PARAM_ANIMATABLE);
6209
6210   /**
6211    * ClutterActor:rotation-angle-z:
6212    *
6213    * The rotation angle on the Z axis
6214    *
6215    * The #ClutterActor:rotation-angle-z property is animatable.
6216    *
6217    * Since: 0.6
6218    */
6219   obj_props[PROP_ROTATION_ANGLE_Z] =
6220     g_param_spec_double ("rotation-angle-z",
6221                          P_("Rotation Angle Z"),
6222                          P_("The rotation angle on the Z axis"),
6223                          -G_MAXDOUBLE, G_MAXDOUBLE,
6224                          0.0,
6225                          G_PARAM_READWRITE |
6226                          G_PARAM_STATIC_STRINGS |
6227                          CLUTTER_PARAM_ANIMATABLE);
6228
6229   /**
6230    * ClutterActor:rotation-center-x:
6231    *
6232    * The rotation center on the X axis.
6233    *
6234    * Since: 0.6
6235    */
6236   obj_props[PROP_ROTATION_CENTER_X] =
6237     g_param_spec_boxed ("rotation-center-x",
6238                         P_("Rotation Center X"),
6239                         P_("The rotation center on the X axis"),
6240                         CLUTTER_TYPE_VERTEX,
6241                         CLUTTER_PARAM_READWRITE);
6242
6243   /**
6244    * ClutterActor:rotation-center-y:
6245    *
6246    * The rotation center on the Y axis.
6247    *
6248    * Since: 0.6
6249    */
6250   obj_props[PROP_ROTATION_CENTER_Y] =
6251     g_param_spec_boxed ("rotation-center-y",
6252                         P_("Rotation Center Y"),
6253                         P_("The rotation center on the Y axis"),
6254                         CLUTTER_TYPE_VERTEX,
6255                         CLUTTER_PARAM_READWRITE);
6256
6257   /**
6258    * ClutterActor:rotation-center-z:
6259    *
6260    * The rotation center on the Z axis.
6261    *
6262    * Since: 0.6
6263    */
6264   obj_props[PROP_ROTATION_CENTER_Z] =
6265     g_param_spec_boxed ("rotation-center-z",
6266                         P_("Rotation Center Z"),
6267                         P_("The rotation center on the Z axis"),
6268                         CLUTTER_TYPE_VERTEX,
6269                         CLUTTER_PARAM_READWRITE);
6270
6271   /**
6272    * ClutterActor:rotation-center-z-gravity:
6273    *
6274    * The rotation center on the Z axis expressed as a #ClutterGravity.
6275    *
6276    * Since: 1.0
6277    */
6278   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6279     g_param_spec_enum ("rotation-center-z-gravity",
6280                        P_("Rotation Center Z Gravity"),
6281                        P_("Center point for rotation around the Z axis"),
6282                        CLUTTER_TYPE_GRAVITY,
6283                        CLUTTER_GRAVITY_NONE,
6284                        CLUTTER_PARAM_READWRITE);
6285
6286   /**
6287    * ClutterActor:anchor-x:
6288    *
6289    * The X coordinate of an actor's anchor point, relative to
6290    * the actor coordinate space, in pixels
6291    *
6292    * Since: 0.8
6293    */
6294   obj_props[PROP_ANCHOR_X] =
6295     g_param_spec_float ("anchor-x",
6296                         P_("Anchor X"),
6297                         P_("X coordinate of the anchor point"),
6298                         -G_MAXFLOAT, G_MAXFLOAT,
6299                         0,
6300                         CLUTTER_PARAM_READWRITE);
6301
6302   /**
6303    * ClutterActor:anchor-y:
6304    *
6305    * The Y coordinate of an actor's anchor point, relative to
6306    * the actor coordinate space, in pixels
6307    *
6308    * Since: 0.8
6309    */
6310   obj_props[PROP_ANCHOR_Y] =
6311     g_param_spec_float ("anchor-y",
6312                         P_("Anchor Y"),
6313                         P_("Y coordinate of the anchor point"),
6314                         -G_MAXFLOAT, G_MAXFLOAT,
6315                         0,
6316                         CLUTTER_PARAM_READWRITE);
6317
6318   /**
6319    * ClutterActor:anchor-gravity:
6320    *
6321    * The anchor point expressed as a #ClutterGravity
6322    *
6323    * Since: 1.0
6324    */
6325   obj_props[PROP_ANCHOR_GRAVITY] =
6326     g_param_spec_enum ("anchor-gravity",
6327                        P_("Anchor Gravity"),
6328                        P_("The anchor point as a ClutterGravity"),
6329                        CLUTTER_TYPE_GRAVITY,
6330                        CLUTTER_GRAVITY_NONE,
6331                        CLUTTER_PARAM_READWRITE);
6332
6333   /**
6334    * ClutterActor:show-on-set-parent:
6335    *
6336    * If %TRUE, the actor is automatically shown when parented.
6337    *
6338    * Calling clutter_actor_hide() on an actor which has not been
6339    * parented will set this property to %FALSE as a side effect.
6340    *
6341    * Since: 0.8
6342    */
6343   obj_props[PROP_SHOW_ON_SET_PARENT] =
6344     g_param_spec_boolean ("show-on-set-parent",
6345                           P_("Show on set parent"),
6346                           P_("Whether the actor is shown when parented"),
6347                           TRUE,
6348                           CLUTTER_PARAM_READWRITE);
6349
6350   /**
6351    * ClutterActor:clip-to-allocation:
6352    *
6353    * Whether the clip region should track the allocated area
6354    * of the actor.
6355    *
6356    * This property is ignored if a clip area has been explicitly
6357    * set using clutter_actor_set_clip().
6358    *
6359    * Since: 1.0
6360    */
6361   obj_props[PROP_CLIP_TO_ALLOCATION] =
6362     g_param_spec_boolean ("clip-to-allocation",
6363                           P_("Clip to Allocation"),
6364                           P_("Sets the clip region to track the actor's allocation"),
6365                           FALSE,
6366                           CLUTTER_PARAM_READWRITE);
6367
6368   /**
6369    * ClutterActor:text-direction:
6370    *
6371    * The direction of the text inside a #ClutterActor.
6372    *
6373    * Since: 1.0
6374    */
6375   obj_props[PROP_TEXT_DIRECTION] =
6376     g_param_spec_enum ("text-direction",
6377                        P_("Text Direction"),
6378                        P_("Direction of the text"),
6379                        CLUTTER_TYPE_TEXT_DIRECTION,
6380                        CLUTTER_TEXT_DIRECTION_LTR,
6381                        CLUTTER_PARAM_READWRITE);
6382
6383   /**
6384    * ClutterActor:has-pointer:
6385    *
6386    * Whether the actor contains the pointer of a #ClutterInputDevice
6387    * or not.
6388    *
6389    * Since: 1.2
6390    */
6391   obj_props[PROP_HAS_POINTER] =
6392     g_param_spec_boolean ("has-pointer",
6393                           P_("Has Pointer"),
6394                           P_("Whether the actor contains the pointer of an input device"),
6395                           FALSE,
6396                           CLUTTER_PARAM_READABLE);
6397
6398   /**
6399    * ClutterActor:actions:
6400    *
6401    * Adds a #ClutterAction to the actor
6402    *
6403    * Since: 1.4
6404    */
6405   obj_props[PROP_ACTIONS] =
6406     g_param_spec_object ("actions",
6407                          P_("Actions"),
6408                          P_("Adds an action to the actor"),
6409                          CLUTTER_TYPE_ACTION,
6410                          CLUTTER_PARAM_WRITABLE);
6411
6412   /**
6413    * ClutterActor:constraints:
6414    *
6415    * Adds a #ClutterConstraint to the actor
6416    *
6417    * Since: 1.4
6418    */
6419   obj_props[PROP_CONSTRAINTS] =
6420     g_param_spec_object ("constraints",
6421                          P_("Constraints"),
6422                          P_("Adds a constraint to the actor"),
6423                          CLUTTER_TYPE_CONSTRAINT,
6424                          CLUTTER_PARAM_WRITABLE);
6425
6426   /**
6427    * ClutterActor:effect:
6428    *
6429    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6430    *
6431    * Since: 1.4
6432    */
6433   obj_props[PROP_EFFECT] =
6434     g_param_spec_object ("effect",
6435                          P_("Effect"),
6436                          P_("Add an effect to be applied on the actor"),
6437                          CLUTTER_TYPE_EFFECT,
6438                          CLUTTER_PARAM_WRITABLE);
6439
6440   /**
6441    * ClutterActor:layout-manager:
6442    *
6443    * A delegate object for controlling the layout of the children of
6444    * an actor.
6445    *
6446    * Since: 1.10
6447    */
6448   obj_props[PROP_LAYOUT_MANAGER] =
6449     g_param_spec_object ("layout-manager",
6450                          P_("Layout Manager"),
6451                          P_("The object controlling the layout of an actor's children"),
6452                          CLUTTER_TYPE_LAYOUT_MANAGER,
6453                          CLUTTER_PARAM_READWRITE);
6454
6455   /**
6456    * ClutterActor:x-expand:
6457    *
6458    * Whether a layout manager should assign more space to the actor on
6459    * the X axis.
6460    *
6461    * Since: 1.12
6462    */
6463   obj_props[PROP_X_EXPAND] =
6464     g_param_spec_boolean ("x-expand",
6465                           P_("X Expand"),
6466                           P_("Whether extra horizontal space should be assigned to the actor"),
6467                           FALSE,
6468                           G_PARAM_READWRITE |
6469                           G_PARAM_STATIC_STRINGS);
6470
6471   /**
6472    * ClutterActor:y-expand:
6473    *
6474    * Whether a layout manager should assign more space to the actor on
6475    * the Y axis.
6476    *
6477    * Since: 1.12
6478    */
6479   obj_props[PROP_Y_EXPAND] =
6480     g_param_spec_boolean ("y-expand",
6481                           P_("Y Expand"),
6482                           P_("Whether extra vertical space should be assigned to the actor"),
6483                           FALSE,
6484                           G_PARAM_READWRITE |
6485                           G_PARAM_STATIC_STRINGS);
6486
6487   /**
6488    * ClutterActor:x-align:
6489    *
6490    * The alignment of an actor on the X axis, if the actor has been given
6491    * extra space for its allocation. See also the #ClutterActor:x-expand
6492    * property.
6493    *
6494    * Since: 1.10
6495    */
6496   obj_props[PROP_X_ALIGN] =
6497     g_param_spec_enum ("x-align",
6498                        P_("X Alignment"),
6499                        P_("The alignment of the actor on the X axis within its allocation"),
6500                        CLUTTER_TYPE_ACTOR_ALIGN,
6501                        CLUTTER_ACTOR_ALIGN_FILL,
6502                        CLUTTER_PARAM_READWRITE);
6503
6504   /**
6505    * ClutterActor:y-align:
6506    *
6507    * The alignment of an actor on the Y axis, if the actor has been given
6508    * extra space for its allocation.
6509    *
6510    * Since: 1.10
6511    */
6512   obj_props[PROP_Y_ALIGN] =
6513     g_param_spec_enum ("y-align",
6514                        P_("Y Alignment"),
6515                        P_("The alignment of the actor on the Y axis within its allocation"),
6516                        CLUTTER_TYPE_ACTOR_ALIGN,
6517                        CLUTTER_ACTOR_ALIGN_FILL,
6518                        CLUTTER_PARAM_READWRITE);
6519
6520   /**
6521    * ClutterActor:margin-top:
6522    *
6523    * The margin (in pixels) from the top of the actor.
6524    *
6525    * This property adds a margin to the actor's preferred size; the margin
6526    * will be automatically taken into account when allocating the actor.
6527    *
6528    * Since: 1.10
6529    */
6530   obj_props[PROP_MARGIN_TOP] =
6531     g_param_spec_float ("margin-top",
6532                         P_("Margin Top"),
6533                         P_("Extra space at the top"),
6534                         0.0, G_MAXFLOAT,
6535                         0.0,
6536                         CLUTTER_PARAM_READWRITE);
6537
6538   /**
6539    * ClutterActor:margin-bottom:
6540    *
6541    * The margin (in pixels) from the bottom of the actor.
6542    *
6543    * This property adds a margin to the actor's preferred size; the margin
6544    * will be automatically taken into account when allocating the actor.
6545    *
6546    * Since: 1.10
6547    */
6548   obj_props[PROP_MARGIN_BOTTOM] =
6549     g_param_spec_float ("margin-bottom",
6550                         P_("Margin Bottom"),
6551                         P_("Extra space at the bottom"),
6552                         0.0, G_MAXFLOAT,
6553                         0.0,
6554                         CLUTTER_PARAM_READWRITE);
6555
6556   /**
6557    * ClutterActor:margin-left:
6558    *
6559    * The margin (in pixels) from the left of the actor.
6560    *
6561    * This property adds a margin to the actor's preferred size; the margin
6562    * will be automatically taken into account when allocating the actor.
6563    *
6564    * Since: 1.10
6565    */
6566   obj_props[PROP_MARGIN_LEFT] =
6567     g_param_spec_float ("margin-left",
6568                         P_("Margin Left"),
6569                         P_("Extra space at the left"),
6570                         0.0, G_MAXFLOAT,
6571                         0.0,
6572                         CLUTTER_PARAM_READWRITE);
6573
6574   /**
6575    * ClutterActor:margin-right:
6576    *
6577    * The margin (in pixels) from the right of the actor.
6578    *
6579    * This property adds a margin to the actor's preferred size; the margin
6580    * will be automatically taken into account when allocating the actor.
6581    *
6582    * Since: 1.10
6583    */
6584   obj_props[PROP_MARGIN_RIGHT] =
6585     g_param_spec_float ("margin-right",
6586                         P_("Margin Right"),
6587                         P_("Extra space at the right"),
6588                         0.0, G_MAXFLOAT,
6589                         0.0,
6590                         CLUTTER_PARAM_READWRITE);
6591
6592   /**
6593    * ClutterActor:background-color-set:
6594    *
6595    * Whether the #ClutterActor:background-color property has been set.
6596    *
6597    * Since: 1.10
6598    */
6599   obj_props[PROP_BACKGROUND_COLOR_SET] =
6600     g_param_spec_boolean ("background-color-set",
6601                           P_("Background Color Set"),
6602                           P_("Whether the background color is set"),
6603                           FALSE,
6604                           CLUTTER_PARAM_READABLE);
6605
6606   /**
6607    * ClutterActor:background-color:
6608    *
6609    * Paints a solid fill of the actor's allocation using the specified
6610    * color.
6611    *
6612    * The #ClutterActor:background-color property is animatable.
6613    *
6614    * Since: 1.10
6615    */
6616   obj_props[PROP_BACKGROUND_COLOR] =
6617     clutter_param_spec_color ("background-color",
6618                               P_("Background color"),
6619                               P_("The actor's background color"),
6620                               CLUTTER_COLOR_Transparent,
6621                               G_PARAM_READWRITE |
6622                               G_PARAM_STATIC_STRINGS |
6623                               CLUTTER_PARAM_ANIMATABLE);
6624
6625   /**
6626    * ClutterActor:first-child:
6627    *
6628    * The actor's first child.
6629    *
6630    * Since: 1.10
6631    */
6632   obj_props[PROP_FIRST_CHILD] =
6633     g_param_spec_object ("first-child",
6634                          P_("First Child"),
6635                          P_("The actor's first child"),
6636                          CLUTTER_TYPE_ACTOR,
6637                          CLUTTER_PARAM_READABLE);
6638
6639   /**
6640    * ClutterActor:last-child:
6641    *
6642    * The actor's last child.
6643    *
6644    * Since: 1.10
6645    */
6646   obj_props[PROP_LAST_CHILD] =
6647     g_param_spec_object ("last-child",
6648                          P_("Last Child"),
6649                          P_("The actor's last child"),
6650                          CLUTTER_TYPE_ACTOR,
6651                          CLUTTER_PARAM_READABLE);
6652
6653   /**
6654    * ClutterActor:content:
6655    *
6656    * The #ClutterContent implementation that controls the content
6657    * of the actor.
6658    *
6659    * Since: 1.10
6660    */
6661   obj_props[PROP_CONTENT] =
6662     g_param_spec_object ("content",
6663                          P_("Content"),
6664                          P_("Delegate object for painting the actor's content"),
6665                          CLUTTER_TYPE_CONTENT,
6666                          CLUTTER_PARAM_READWRITE);
6667
6668   /**
6669    * ClutterActor:content-gravity:
6670    *
6671    * The alignment that should be honoured by the #ClutterContent
6672    * set with the #ClutterActor:content property.
6673    *
6674    * Changing the value of this property will change the bounding box of
6675    * the content; you can use the #ClutterActor:content-box property to
6676    * get the position and size of the content within the actor's
6677    * allocation.
6678    *
6679    * This property is meaningful only for #ClutterContent implementations
6680    * that have a preferred size, and if the preferred size is smaller than
6681    * the actor's allocation.
6682    *
6683    * The #ClutterActor:content-gravity property is animatable.
6684    *
6685    * Since: 1.10
6686    */
6687   obj_props[PROP_CONTENT_GRAVITY] =
6688     g_param_spec_enum ("content-gravity",
6689                        P_("Content Gravity"),
6690                        P_("Alignment of the actor's content"),
6691                        CLUTTER_TYPE_CONTENT_GRAVITY,
6692                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6693                        CLUTTER_PARAM_READWRITE);
6694
6695   /**
6696    * ClutterActor:content-box:
6697    *
6698    * The bounding box for the #ClutterContent used by the actor.
6699    *
6700    * The value of this property is controlled by the #ClutterActor:allocation
6701    * and #ClutterActor:content-gravity properties of #ClutterActor.
6702    *
6703    * The bounding box for the content is guaranteed to never exceed the
6704    * allocation's of the actor.
6705    *
6706    * Since: 1.10
6707    */
6708   obj_props[PROP_CONTENT_BOX] =
6709     g_param_spec_boxed ("content-box",
6710                         P_("Content Box"),
6711                         P_("The bounding box of the actor's content"),
6712                         CLUTTER_TYPE_ACTOR_BOX,
6713                         G_PARAM_READABLE |
6714                         G_PARAM_STATIC_STRINGS |
6715                         CLUTTER_PARAM_ANIMATABLE);
6716
6717   obj_props[PROP_MINIFICATION_FILTER] =
6718     g_param_spec_enum ("minification-filter",
6719                        P_("Minification Filter"),
6720                        P_("The filter used when reducing the size of the content"),
6721                        CLUTTER_TYPE_SCALING_FILTER,
6722                        CLUTTER_SCALING_FILTER_LINEAR,
6723                        CLUTTER_PARAM_READWRITE);
6724
6725   obj_props[PROP_MAGNIFICATION_FILTER] =
6726     g_param_spec_enum ("magnification-filter",
6727                        P_("Magnification Filter"),
6728                        P_("The filter used when increasing the size of the content"),
6729                        CLUTTER_TYPE_SCALING_FILTER,
6730                        CLUTTER_SCALING_FILTER_LINEAR,
6731                        CLUTTER_PARAM_READWRITE);
6732
6733   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6734
6735   /**
6736    * ClutterActor::destroy:
6737    * @actor: the #ClutterActor which emitted the signal
6738    *
6739    * The ::destroy signal notifies that all references held on the
6740    * actor which emitted it should be released.
6741    *
6742    * The ::destroy signal should be used by all holders of a reference
6743    * on @actor.
6744    *
6745    * This signal might result in the finalization of the #ClutterActor
6746    * if all references are released.
6747    *
6748    * Composite actors and actors implementing the #ClutterContainer
6749    * interface should override the default implementation of the
6750    * class handler of this signal and call clutter_actor_destroy() on
6751    * their children. When overriding the default class handler, it is
6752    * required to chain up to the parent's implementation.
6753    *
6754    * Since: 0.2
6755    */
6756   actor_signals[DESTROY] =
6757     g_signal_new (I_("destroy"),
6758                   G_TYPE_FROM_CLASS (object_class),
6759                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6760                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6761                   NULL, NULL,
6762                   _clutter_marshal_VOID__VOID,
6763                   G_TYPE_NONE, 0);
6764   /**
6765    * ClutterActor::show:
6766    * @actor: the object which received the signal
6767    *
6768    * The ::show signal is emitted when an actor is visible and
6769    * rendered on the stage.
6770    *
6771    * Since: 0.2
6772    */
6773   actor_signals[SHOW] =
6774     g_signal_new (I_("show"),
6775                   G_TYPE_FROM_CLASS (object_class),
6776                   G_SIGNAL_RUN_FIRST,
6777                   G_STRUCT_OFFSET (ClutterActorClass, show),
6778                   NULL, NULL,
6779                   _clutter_marshal_VOID__VOID,
6780                   G_TYPE_NONE, 0);
6781   /**
6782    * ClutterActor::hide:
6783    * @actor: the object which received the signal
6784    *
6785    * The ::hide signal is emitted when an actor is no longer rendered
6786    * on the stage.
6787    *
6788    * Since: 0.2
6789    */
6790   actor_signals[HIDE] =
6791     g_signal_new (I_("hide"),
6792                   G_TYPE_FROM_CLASS (object_class),
6793                   G_SIGNAL_RUN_FIRST,
6794                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6795                   NULL, NULL,
6796                   _clutter_marshal_VOID__VOID,
6797                   G_TYPE_NONE, 0);
6798   /**
6799    * ClutterActor::parent-set:
6800    * @actor: the object which received the signal
6801    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6802    *
6803    * This signal is emitted when the parent of the actor changes.
6804    *
6805    * Since: 0.2
6806    */
6807   actor_signals[PARENT_SET] =
6808     g_signal_new (I_("parent-set"),
6809                   G_TYPE_FROM_CLASS (object_class),
6810                   G_SIGNAL_RUN_LAST,
6811                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6812                   NULL, NULL,
6813                   _clutter_marshal_VOID__OBJECT,
6814                   G_TYPE_NONE, 1,
6815                   CLUTTER_TYPE_ACTOR);
6816
6817   /**
6818    * ClutterActor::queue-redraw:
6819    * @actor: the actor we're bubbling the redraw request through
6820    * @origin: the actor which initiated the redraw request
6821    *
6822    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6823    * is called on @origin.
6824    *
6825    * The default implementation for #ClutterActor chains up to the
6826    * parent actor and queues a redraw on the parent, thus "bubbling"
6827    * the redraw queue up through the actor graph. The default
6828    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6829    * in a main loop idle handler.
6830    *
6831    * Note that the @origin actor may be the stage, or a container; it
6832    * does not have to be a leaf node in the actor graph.
6833    *
6834    * Toolkits embedding a #ClutterStage which require a redraw and
6835    * relayout cycle can stop the emission of this signal using the
6836    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6837    * themselves, like:
6838    *
6839    * |[
6840    *   static void
6841    *   on_redraw_complete (gpointer data)
6842    *   {
6843    *     ClutterStage *stage = data;
6844    *
6845    *     /&ast; execute the Clutter drawing pipeline &ast;/
6846    *     clutter_stage_ensure_redraw (stage);
6847    *   }
6848    *
6849    *   static void
6850    *   on_stage_queue_redraw (ClutterStage *stage)
6851    *   {
6852    *     /&ast; this prevents the default handler to run &ast;/
6853    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6854    *
6855    *     /&ast; queue a redraw with the host toolkit and call
6856    *      &ast; a function when the redraw has been completed
6857    *      &ast;/
6858    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6859    *   }
6860    * ]|
6861    *
6862    * <note><para>This signal is emitted before the Clutter paint
6863    * pipeline is executed. If you want to know when the pipeline has
6864    * been completed you should connect to the ::paint signal on the
6865    * Stage with g_signal_connect_after().</para></note>
6866    *
6867    * Since: 1.0
6868    */
6869   actor_signals[QUEUE_REDRAW] =
6870     g_signal_new (I_("queue-redraw"),
6871                   G_TYPE_FROM_CLASS (object_class),
6872                   G_SIGNAL_RUN_LAST |
6873                   G_SIGNAL_NO_HOOKS,
6874                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6875                   NULL, NULL,
6876                   _clutter_marshal_VOID__OBJECT,
6877                   G_TYPE_NONE, 1,
6878                   CLUTTER_TYPE_ACTOR);
6879
6880   /**
6881    * ClutterActor::queue-relayout:
6882    * @actor: the actor being queued for relayout
6883    *
6884    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6885    * is called on an actor.
6886    *
6887    * The default implementation for #ClutterActor chains up to the
6888    * parent actor and queues a relayout on the parent, thus "bubbling"
6889    * the relayout queue up through the actor graph.
6890    *
6891    * The main purpose of this signal is to allow relayout to be propagated
6892    * properly in the procense of #ClutterClone actors. Applications will
6893    * not normally need to connect to this signal.
6894    *
6895    * Since: 1.2
6896    */
6897   actor_signals[QUEUE_RELAYOUT] =
6898     g_signal_new (I_("queue-relayout"),
6899                   G_TYPE_FROM_CLASS (object_class),
6900                   G_SIGNAL_RUN_LAST |
6901                   G_SIGNAL_NO_HOOKS,
6902                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6903                   NULL, NULL,
6904                   _clutter_marshal_VOID__VOID,
6905                   G_TYPE_NONE, 0);
6906
6907   /**
6908    * ClutterActor::event:
6909    * @actor: the actor which received the event
6910    * @event: a #ClutterEvent
6911    *
6912    * The ::event signal is emitted each time an event is received
6913    * by the @actor. This signal will be emitted on every actor,
6914    * following the hierarchy chain, until it reaches the top-level
6915    * container (the #ClutterStage).
6916    *
6917    * Return value: %TRUE if the event has been handled by the actor,
6918    *   or %FALSE to continue the emission.
6919    *
6920    * Since: 0.6
6921    */
6922   actor_signals[EVENT] =
6923     g_signal_new (I_("event"),
6924                   G_TYPE_FROM_CLASS (object_class),
6925                   G_SIGNAL_RUN_LAST,
6926                   G_STRUCT_OFFSET (ClutterActorClass, event),
6927                   _clutter_boolean_handled_accumulator, NULL,
6928                   _clutter_marshal_BOOLEAN__BOXED,
6929                   G_TYPE_BOOLEAN, 1,
6930                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6931   /**
6932    * ClutterActor::button-press-event:
6933    * @actor: the actor which received the event
6934    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6935    *
6936    * The ::button-press-event signal is emitted each time a mouse button
6937    * is pressed on @actor.
6938    *
6939    * Return value: %TRUE if the event has been handled by the actor,
6940    *   or %FALSE to continue the emission.
6941    *
6942    * Since: 0.6
6943    */
6944   actor_signals[BUTTON_PRESS_EVENT] =
6945     g_signal_new (I_("button-press-event"),
6946                   G_TYPE_FROM_CLASS (object_class),
6947                   G_SIGNAL_RUN_LAST,
6948                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6949                   _clutter_boolean_handled_accumulator, NULL,
6950                   _clutter_marshal_BOOLEAN__BOXED,
6951                   G_TYPE_BOOLEAN, 1,
6952                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6953   /**
6954    * ClutterActor::button-release-event:
6955    * @actor: the actor which received the event
6956    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6957    *
6958    * The ::button-release-event signal is emitted each time a mouse button
6959    * is released on @actor.
6960    *
6961    * Return value: %TRUE if the event has been handled by the actor,
6962    *   or %FALSE to continue the emission.
6963    *
6964    * Since: 0.6
6965    */
6966   actor_signals[BUTTON_RELEASE_EVENT] =
6967     g_signal_new (I_("button-release-event"),
6968                   G_TYPE_FROM_CLASS (object_class),
6969                   G_SIGNAL_RUN_LAST,
6970                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6971                   _clutter_boolean_handled_accumulator, NULL,
6972                   _clutter_marshal_BOOLEAN__BOXED,
6973                   G_TYPE_BOOLEAN, 1,
6974                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6975   /**
6976    * ClutterActor::scroll-event:
6977    * @actor: the actor which received the event
6978    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6979    *
6980    * The ::scroll-event signal is emitted each time the mouse is
6981    * scrolled on @actor
6982    *
6983    * Return value: %TRUE if the event has been handled by the actor,
6984    *   or %FALSE to continue the emission.
6985    *
6986    * Since: 0.6
6987    */
6988   actor_signals[SCROLL_EVENT] =
6989     g_signal_new (I_("scroll-event"),
6990                   G_TYPE_FROM_CLASS (object_class),
6991                   G_SIGNAL_RUN_LAST,
6992                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6993                   _clutter_boolean_handled_accumulator, NULL,
6994                   _clutter_marshal_BOOLEAN__BOXED,
6995                   G_TYPE_BOOLEAN, 1,
6996                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6997   /**
6998    * ClutterActor::key-press-event:
6999    * @actor: the actor which received the event
7000    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7001    *
7002    * The ::key-press-event signal is emitted each time a keyboard button
7003    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
7004    *
7005    * Return value: %TRUE if the event has been handled by the actor,
7006    *   or %FALSE to continue the emission.
7007    *
7008    * Since: 0.6
7009    */
7010   actor_signals[KEY_PRESS_EVENT] =
7011     g_signal_new (I_("key-press-event"),
7012                   G_TYPE_FROM_CLASS (object_class),
7013                   G_SIGNAL_RUN_LAST,
7014                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
7015                   _clutter_boolean_handled_accumulator, NULL,
7016                   _clutter_marshal_BOOLEAN__BOXED,
7017                   G_TYPE_BOOLEAN, 1,
7018                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7019   /**
7020    * ClutterActor::key-release-event:
7021    * @actor: the actor which received the event
7022    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7023    *
7024    * The ::key-release-event signal is emitted each time a keyboard button
7025    * is released while @actor has key focus (see
7026    * clutter_stage_set_key_focus()).
7027    *
7028    * Return value: %TRUE if the event has been handled by the actor,
7029    *   or %FALSE to continue the emission.
7030    *
7031    * Since: 0.6
7032    */
7033   actor_signals[KEY_RELEASE_EVENT] =
7034     g_signal_new (I_("key-release-event"),
7035                   G_TYPE_FROM_CLASS (object_class),
7036                   G_SIGNAL_RUN_LAST,
7037                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
7038                   _clutter_boolean_handled_accumulator, NULL,
7039                   _clutter_marshal_BOOLEAN__BOXED,
7040                   G_TYPE_BOOLEAN, 1,
7041                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7042   /**
7043    * ClutterActor::motion-event:
7044    * @actor: the actor which received the event
7045    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
7046    *
7047    * The ::motion-event signal is emitted each time the mouse pointer is
7048    * moved over @actor.
7049    *
7050    * Return value: %TRUE if the event has been handled by the actor,
7051    *   or %FALSE to continue the emission.
7052    *
7053    * Since: 0.6
7054    */
7055   actor_signals[MOTION_EVENT] =
7056     g_signal_new (I_("motion-event"),
7057                   G_TYPE_FROM_CLASS (object_class),
7058                   G_SIGNAL_RUN_LAST,
7059                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
7060                   _clutter_boolean_handled_accumulator, NULL,
7061                   _clutter_marshal_BOOLEAN__BOXED,
7062                   G_TYPE_BOOLEAN, 1,
7063                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7064
7065   /**
7066    * ClutterActor::key-focus-in:
7067    * @actor: the actor which now has key focus
7068    *
7069    * The ::key-focus-in signal is emitted when @actor receives key focus.
7070    *
7071    * Since: 0.6
7072    */
7073   actor_signals[KEY_FOCUS_IN] =
7074     g_signal_new (I_("key-focus-in"),
7075                   G_TYPE_FROM_CLASS (object_class),
7076                   G_SIGNAL_RUN_LAST,
7077                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
7078                   NULL, NULL,
7079                   _clutter_marshal_VOID__VOID,
7080                   G_TYPE_NONE, 0);
7081
7082   /**
7083    * ClutterActor::key-focus-out:
7084    * @actor: the actor which now has key focus
7085    *
7086    * The ::key-focus-out signal is emitted when @actor loses key focus.
7087    *
7088    * Since: 0.6
7089    */
7090   actor_signals[KEY_FOCUS_OUT] =
7091     g_signal_new (I_("key-focus-out"),
7092                   G_TYPE_FROM_CLASS (object_class),
7093                   G_SIGNAL_RUN_LAST,
7094                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
7095                   NULL, NULL,
7096                   _clutter_marshal_VOID__VOID,
7097                   G_TYPE_NONE, 0);
7098
7099   /**
7100    * ClutterActor::enter-event:
7101    * @actor: the actor which the pointer has entered.
7102    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7103    *
7104    * The ::enter-event signal is emitted when the pointer enters the @actor
7105    *
7106    * Return value: %TRUE if the event has been handled by the actor,
7107    *   or %FALSE to continue the emission.
7108    *
7109    * Since: 0.6
7110    */
7111   actor_signals[ENTER_EVENT] =
7112     g_signal_new (I_("enter-event"),
7113                   G_TYPE_FROM_CLASS (object_class),
7114                   G_SIGNAL_RUN_LAST,
7115                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
7116                   _clutter_boolean_handled_accumulator, NULL,
7117                   _clutter_marshal_BOOLEAN__BOXED,
7118                   G_TYPE_BOOLEAN, 1,
7119                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7120
7121   /**
7122    * ClutterActor::leave-event:
7123    * @actor: the actor which the pointer has left
7124    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7125    *
7126    * The ::leave-event signal is emitted when the pointer leaves the @actor.
7127    *
7128    * Return value: %TRUE if the event has been handled by the actor,
7129    *   or %FALSE to continue the emission.
7130    *
7131    * Since: 0.6
7132    */
7133   actor_signals[LEAVE_EVENT] =
7134     g_signal_new (I_("leave-event"),
7135                   G_TYPE_FROM_CLASS (object_class),
7136                   G_SIGNAL_RUN_LAST,
7137                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7138                   _clutter_boolean_handled_accumulator, NULL,
7139                   _clutter_marshal_BOOLEAN__BOXED,
7140                   G_TYPE_BOOLEAN, 1,
7141                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7142
7143   /**
7144    * ClutterActor::captured-event:
7145    * @actor: the actor which received the signal
7146    * @event: a #ClutterEvent
7147    *
7148    * The ::captured-event signal is emitted when an event is captured
7149    * by Clutter. This signal will be emitted starting from the top-level
7150    * container (the #ClutterStage) to the actor which received the event
7151    * going down the hierarchy. This signal can be used to intercept every
7152    * event before the specialized events (like
7153    * ClutterActor::button-press-event or ::key-released-event) are
7154    * emitted.
7155    *
7156    * Return value: %TRUE if the event has been handled by the actor,
7157    *   or %FALSE to continue the emission.
7158    *
7159    * Since: 0.6
7160    */
7161   actor_signals[CAPTURED_EVENT] =
7162     g_signal_new (I_("captured-event"),
7163                   G_TYPE_FROM_CLASS (object_class),
7164                   G_SIGNAL_RUN_LAST,
7165                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7166                   _clutter_boolean_handled_accumulator, NULL,
7167                   _clutter_marshal_BOOLEAN__BOXED,
7168                   G_TYPE_BOOLEAN, 1,
7169                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7170
7171   /**
7172    * ClutterActor::paint:
7173    * @actor: the #ClutterActor that received the signal
7174    *
7175    * The ::paint signal is emitted each time an actor is being painted.
7176    *
7177    * Subclasses of #ClutterActor should override the class signal handler
7178    * and paint themselves in that function.
7179    *
7180    * It is possible to connect a handler to the ::paint signal in order
7181    * to set up some custom aspect of a paint.
7182    *
7183    * Since: 0.8
7184    */
7185   actor_signals[PAINT] =
7186     g_signal_new (I_("paint"),
7187                   G_TYPE_FROM_CLASS (object_class),
7188                   G_SIGNAL_RUN_LAST |
7189                   G_SIGNAL_NO_HOOKS,
7190                   G_STRUCT_OFFSET (ClutterActorClass, paint),
7191                   NULL, NULL,
7192                   _clutter_marshal_VOID__VOID,
7193                   G_TYPE_NONE, 0);
7194   /**
7195    * ClutterActor::realize:
7196    * @actor: the #ClutterActor that received the signal
7197    *
7198    * The ::realize signal is emitted each time an actor is being
7199    * realized.
7200    *
7201    * Since: 0.8
7202    */
7203   actor_signals[REALIZE] =
7204     g_signal_new (I_("realize"),
7205                   G_TYPE_FROM_CLASS (object_class),
7206                   G_SIGNAL_RUN_LAST,
7207                   G_STRUCT_OFFSET (ClutterActorClass, realize),
7208                   NULL, NULL,
7209                   _clutter_marshal_VOID__VOID,
7210                   G_TYPE_NONE, 0);
7211   /**
7212    * ClutterActor::unrealize:
7213    * @actor: the #ClutterActor that received the signal
7214    *
7215    * The ::unrealize signal is emitted each time an actor is being
7216    * unrealized.
7217    *
7218    * Since: 0.8
7219    */
7220   actor_signals[UNREALIZE] =
7221     g_signal_new (I_("unrealize"),
7222                   G_TYPE_FROM_CLASS (object_class),
7223                   G_SIGNAL_RUN_LAST,
7224                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7225                   NULL, NULL,
7226                   _clutter_marshal_VOID__VOID,
7227                   G_TYPE_NONE, 0);
7228
7229   /**
7230    * ClutterActor::pick:
7231    * @actor: the #ClutterActor that received the signal
7232    * @color: the #ClutterColor to be used when picking
7233    *
7234    * The ::pick signal is emitted each time an actor is being painted
7235    * in "pick mode". The pick mode is used to identify the actor during
7236    * the event handling phase, or by clutter_stage_get_actor_at_pos().
7237    * The actor should paint its shape using the passed @pick_color.
7238    *
7239    * Subclasses of #ClutterActor should override the class signal handler
7240    * and paint themselves in that function.
7241    *
7242    * It is possible to connect a handler to the ::pick signal in order
7243    * to set up some custom aspect of a paint in pick mode.
7244    *
7245    * Since: 1.0
7246    */
7247   actor_signals[PICK] =
7248     g_signal_new (I_("pick"),
7249                   G_TYPE_FROM_CLASS (object_class),
7250                   G_SIGNAL_RUN_LAST,
7251                   G_STRUCT_OFFSET (ClutterActorClass, pick),
7252                   NULL, NULL,
7253                   _clutter_marshal_VOID__BOXED,
7254                   G_TYPE_NONE, 1,
7255                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7256
7257   /**
7258    * ClutterActor::allocation-changed:
7259    * @actor: the #ClutterActor that emitted the signal
7260    * @box: a #ClutterActorBox with the new allocation
7261    * @flags: #ClutterAllocationFlags for the allocation
7262    *
7263    * The ::allocation-changed signal is emitted when the
7264    * #ClutterActor:allocation property changes. Usually, application
7265    * code should just use the notifications for the :allocation property
7266    * but if you want to track the allocation flags as well, for instance
7267    * to know whether the absolute origin of @actor changed, then you might
7268    * want use this signal instead.
7269    *
7270    * Since: 1.0
7271    */
7272   actor_signals[ALLOCATION_CHANGED] =
7273     g_signal_new (I_("allocation-changed"),
7274                   G_TYPE_FROM_CLASS (object_class),
7275                   G_SIGNAL_RUN_LAST,
7276                   0,
7277                   NULL, NULL,
7278                   _clutter_marshal_VOID__BOXED_FLAGS,
7279                   G_TYPE_NONE, 2,
7280                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7281                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7282
7283   /**
7284    * ClutterActor::transitions-completed:
7285    * @actor: a #ClutterActor
7286    *
7287    * The ::transitions-completed signal is emitted once all transitions
7288    * involving @actor are complete.
7289    *
7290    * Since: 1.10
7291    */
7292   actor_signals[TRANSITIONS_COMPLETED] =
7293     g_signal_new (I_("transitions-completed"),
7294                   G_TYPE_FROM_CLASS (object_class),
7295                   G_SIGNAL_RUN_LAST,
7296                   0,
7297                   NULL, NULL,
7298                   _clutter_marshal_VOID__VOID,
7299                   G_TYPE_NONE, 0);
7300 }
7301
7302 static void
7303 clutter_actor_init (ClutterActor *self)
7304 {
7305   ClutterActorPrivate *priv;
7306
7307   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7308
7309   priv->id = _clutter_context_acquire_id (self);
7310   priv->pick_id = -1;
7311
7312   priv->opacity = 0xff;
7313   priv->show_on_set_parent = TRUE;
7314
7315   priv->needs_width_request = TRUE;
7316   priv->needs_height_request = TRUE;
7317   priv->needs_allocation = TRUE;
7318
7319   priv->cached_width_age = 1;
7320   priv->cached_height_age = 1;
7321
7322   priv->opacity_override = -1;
7323   priv->enable_model_view_transform = TRUE;
7324
7325   /* Initialize an empty paint volume to start with */
7326   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7327   priv->last_paint_volume_valid = TRUE;
7328
7329   priv->transform_valid = FALSE;
7330
7331   /* the default is to stretch the content, to match the
7332    * current behaviour of basically all actors. also, it's
7333    * the easiest thing to compute.
7334    */
7335   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7336   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7337   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7338
7339   /* this flag will be set to TRUE if the actor gets a child
7340    * or if the [xy]-expand flags are explicitly set; until
7341    * then, the actor does not need to expand.
7342    *
7343    * this also allows us to avoid computing the expand flag
7344    * when building up a scene.
7345    */
7346   priv->needs_compute_expand = FALSE;
7347 }
7348
7349 /**
7350  * clutter_actor_new:
7351  *
7352  * Creates a new #ClutterActor.
7353  *
7354  * A newly created actor has a floating reference, which will be sunk
7355  * when it is added to another actor.
7356  *
7357  * Return value: (transfer full): the newly created #ClutterActor
7358  *
7359  * Since: 1.10
7360  */
7361 ClutterActor *
7362 clutter_actor_new (void)
7363 {
7364   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7365 }
7366
7367 /**
7368  * clutter_actor_destroy:
7369  * @self: a #ClutterActor
7370  *
7371  * Destroys an actor.  When an actor is destroyed, it will break any
7372  * references it holds to other objects.  If the actor is inside a
7373  * container, the actor will be removed.
7374  *
7375  * When you destroy a container, its children will be destroyed as well.
7376  *
7377  * Note: you cannot destroy the #ClutterStage returned by
7378  * clutter_stage_get_default().
7379  */
7380 void
7381 clutter_actor_destroy (ClutterActor *self)
7382 {
7383   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7384
7385   g_object_ref (self);
7386
7387   /* avoid recursion while destroying */
7388   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7389     {
7390       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7391
7392       g_object_run_dispose (G_OBJECT (self));
7393
7394       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7395     }
7396
7397   g_object_unref (self);
7398 }
7399
7400 void
7401 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7402                                     ClutterPaintVolume *clip)
7403 {
7404   ClutterActorPrivate *priv = self->priv;
7405   ClutterPaintVolume *pv;
7406   gboolean clipped;
7407
7408   /* Remove queue entry early in the process, otherwise a new
7409      queue_redraw() during signal handling could put back this
7410      object in the stage redraw list (but the entry is freed as
7411      soon as we return from this function, causing a segfault
7412      later)
7413   */
7414   priv->queue_redraw_entry = NULL;
7415
7416   /* If we've been explicitly passed a clip volume then there's
7417    * nothing more to calculate, but otherwise the only thing we know
7418    * is that the change is constrained to the given actor.
7419    *
7420    * The idea is that if we know the paint volume for where the actor
7421    * was last drawn (in eye coordinates) and we also have the paint
7422    * volume for where it will be drawn next (in actor coordinates)
7423    * then if we queue a redraw for both these volumes that will cover
7424    * everything that needs to be redrawn to clear the old view and
7425    * show the latest view of the actor.
7426    *
7427    * Don't clip this redraw if we don't know what position we had for
7428    * the previous redraw since we don't know where to set the clip so
7429    * it will clear the actor as it is currently.
7430    */
7431   if (clip)
7432     {
7433       _clutter_actor_set_queue_redraw_clip (self, clip);
7434       clipped = TRUE;
7435     }
7436   else if (G_LIKELY (priv->last_paint_volume_valid))
7437     {
7438       pv = _clutter_actor_get_paint_volume_mutable (self);
7439       if (pv)
7440         {
7441           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7442
7443           /* make sure we redraw the actors old position... */
7444           _clutter_actor_set_queue_redraw_clip (stage,
7445                                                 &priv->last_paint_volume);
7446           _clutter_actor_signal_queue_redraw (stage, stage);
7447           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7448
7449           /* XXX: Ideally the redraw signal would take a clip volume
7450            * argument, but that would be an ABI break. Until we can
7451            * break the ABI we pass the argument out-of-band
7452            */
7453
7454           /* setup the clip for the actors new position... */
7455           _clutter_actor_set_queue_redraw_clip (self, pv);
7456           clipped = TRUE;
7457         }
7458       else
7459         clipped = FALSE;
7460     }
7461   else
7462     clipped = FALSE;
7463
7464   _clutter_actor_signal_queue_redraw (self, self);
7465
7466   /* Just in case anyone is manually firing redraw signals without
7467    * using the public queue_redraw() API we are careful to ensure that
7468    * our out-of-band clip member is cleared before returning...
7469    *
7470    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7471    */
7472   if (G_LIKELY (clipped))
7473     _clutter_actor_set_queue_redraw_clip (self, NULL);
7474 }
7475
7476 static void
7477 _clutter_actor_get_allocation_clip (ClutterActor *self,
7478                                     ClutterActorBox *clip)
7479 {
7480   ClutterActorBox allocation;
7481
7482   /* XXX: we don't care if we get an out of date allocation here
7483    * because clutter_actor_queue_redraw_with_clip knows to ignore
7484    * the clip if the actor's allocation is invalid.
7485    *
7486    * This is noted because clutter_actor_get_allocation_box does some
7487    * unnecessary work to support buggy code with a comment suggesting
7488    * that it could be changed later which would be good for this use
7489    * case!
7490    */
7491   clutter_actor_get_allocation_box (self, &allocation);
7492
7493   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7494    * actor's own coordinate space but the allocation is in parent
7495    * coordinates */
7496   clip->x1 = 0;
7497   clip->y1 = 0;
7498   clip->x2 = allocation.x2 - allocation.x1;
7499   clip->y2 = allocation.y2 - allocation.y1;
7500 }
7501
7502 void
7503 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7504                                   ClutterRedrawFlags  flags,
7505                                   ClutterPaintVolume *volume,
7506                                   ClutterEffect      *effect)
7507 {
7508   ClutterActorPrivate *priv = self->priv;
7509   ClutterPaintVolume allocation_pv;
7510   ClutterPaintVolume *pv;
7511   gboolean should_free_pv;
7512   ClutterActor *stage;
7513
7514   /* Here's an outline of the actor queue redraw mechanism:
7515    *
7516    * The process starts in one of the following two functions which
7517    * are wrappers for this function:
7518    * clutter_actor_queue_redraw
7519    * _clutter_actor_queue_redraw_with_clip
7520    *
7521    * additionally, an effect can queue a redraw by wrapping this
7522    * function in clutter_effect_queue_rerun
7523    *
7524    * This functions queues an entry in a list associated with the
7525    * stage which is a list of actors that queued a redraw while
7526    * updating the timelines, performing layouting and processing other
7527    * mainloop sources before the next paint starts.
7528    *
7529    * We aim to minimize the processing done at this point because
7530    * there is a good chance other events will happen while updating
7531    * the scenegraph that would invalidate any expensive work we might
7532    * otherwise try to do here. For example we don't try and resolve
7533    * the screen space bounding box of an actor at this stage so as to
7534    * minimize how much of the screen redraw because it's possible
7535    * something else will happen which will force a full redraw anyway.
7536    *
7537    * When all updates are complete and we come to paint the stage then
7538    * we iterate this list and actually emit the "queue-redraw" signals
7539    * for each of the listed actors which will bubble up to the stage
7540    * for each actor and at that point we will transform the actors
7541    * paint volume into screen coordinates to determine the clip region
7542    * for what needs to be redrawn in the next paint.
7543    *
7544    * Besides minimizing redundant work another reason for this
7545    * deferred design is that it's more likely we will be able to
7546    * determine the paint volume of an actor once we've finished
7547    * updating the scenegraph because its allocation should be up to
7548    * date. NB: If we can't determine an actors paint volume then we
7549    * can't automatically queue a clipped redraw which can make a big
7550    * difference to performance.
7551    *
7552    * So the control flow goes like this:
7553    * One of clutter_actor_queue_redraw,
7554    *        _clutter_actor_queue_redraw_with_clip
7555    *     or clutter_effect_queue_rerun
7556    *
7557    * then control moves to:
7558    *   _clutter_stage_queue_actor_redraw
7559    *
7560    * later during _clutter_stage_do_update, once relayouting is done
7561    * and the scenegraph has been updated we will call:
7562    * _clutter_stage_finish_queue_redraws
7563    *
7564    * _clutter_stage_finish_queue_redraws will call
7565    * _clutter_actor_finish_queue_redraw for each listed actor.
7566    * Note: actors *are* allowed to queue further redraws during this
7567    * process (considering clone actors or texture_new_from_actor which
7568    * respond to their source queueing a redraw by queuing a redraw
7569    * themselves). We repeat the process until the list is empty.
7570    *
7571    * This will result in the "queue-redraw" signal being fired for
7572    * each actor which will pass control to the default signal handler:
7573    * clutter_actor_real_queue_redraw
7574    *
7575    * This will bubble up to the stages handler:
7576    * clutter_stage_real_queue_redraw
7577    *
7578    * clutter_stage_real_queue_redraw will transform the actors paint
7579    * volume into screen space and add it as a clip region for the next
7580    * paint.
7581    */
7582
7583   /* ignore queueing a redraw for actors being destroyed */
7584   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7585     return;
7586
7587   stage = _clutter_actor_get_stage_internal (self);
7588
7589   /* Ignore queueing a redraw for actors not descended from a stage */
7590   if (stage == NULL)
7591     return;
7592
7593   /* ignore queueing a redraw on stages that are being destroyed */
7594   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7595     return;
7596
7597   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7598     {
7599       ClutterActorBox allocation_clip;
7600       ClutterVertex origin;
7601
7602       /* If the actor doesn't have a valid allocation then we will
7603        * queue a full stage redraw. */
7604       if (priv->needs_allocation)
7605         {
7606           /* NB: NULL denotes an undefined clip which will result in a
7607            * full redraw... */
7608           _clutter_actor_set_queue_redraw_clip (self, NULL);
7609           _clutter_actor_signal_queue_redraw (self, self);
7610           return;
7611         }
7612
7613       _clutter_paint_volume_init_static (&allocation_pv, self);
7614       pv = &allocation_pv;
7615
7616       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7617
7618       origin.x = allocation_clip.x1;
7619       origin.y = allocation_clip.y1;
7620       origin.z = 0;
7621       clutter_paint_volume_set_origin (pv, &origin);
7622       clutter_paint_volume_set_width (pv,
7623                                       allocation_clip.x2 - allocation_clip.x1);
7624       clutter_paint_volume_set_height (pv,
7625                                        allocation_clip.y2 -
7626                                        allocation_clip.y1);
7627       should_free_pv = TRUE;
7628     }
7629   else
7630     {
7631       pv = volume;
7632       should_free_pv = FALSE;
7633     }
7634
7635   self->priv->queue_redraw_entry =
7636     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7637                                        priv->queue_redraw_entry,
7638                                        self,
7639                                        pv);
7640
7641   if (should_free_pv)
7642     clutter_paint_volume_free (pv);
7643
7644   /* If this is the first redraw queued then we can directly use the
7645      effect parameter */
7646   if (!priv->is_dirty)
7647     priv->effect_to_redraw = effect;
7648   /* Otherwise we need to merge it with the existing effect parameter */
7649   else if (effect != NULL)
7650     {
7651       /* If there's already an effect then we need to use whichever is
7652          later in the chain of actors. Otherwise a full redraw has
7653          already been queued on the actor so we need to ignore the
7654          effect parameter */
7655       if (priv->effect_to_redraw != NULL)
7656         {
7657           if (priv->effects == NULL)
7658             g_warning ("Redraw queued with an effect that is "
7659                        "not applied to the actor");
7660           else
7661             {
7662               const GList *l;
7663
7664               for (l = _clutter_meta_group_peek_metas (priv->effects);
7665                    l != NULL;
7666                    l = l->next)
7667                 {
7668                   if (l->data == priv->effect_to_redraw ||
7669                       l->data == effect)
7670                     priv->effect_to_redraw = l->data;
7671                 }
7672             }
7673         }
7674     }
7675   else
7676     {
7677       /* If no effect is specified then we need to redraw the whole
7678          actor */
7679       priv->effect_to_redraw = NULL;
7680     }
7681
7682   priv->is_dirty = TRUE;
7683 }
7684
7685 /**
7686  * clutter_actor_queue_redraw:
7687  * @self: A #ClutterActor
7688  *
7689  * Queues up a redraw of an actor and any children. The redraw occurs
7690  * once the main loop becomes idle (after the current batch of events
7691  * has been processed, roughly).
7692  *
7693  * Applications rarely need to call this, as redraws are handled
7694  * automatically by modification functions.
7695  *
7696  * This function will not do anything if @self is not visible, or
7697  * if the actor is inside an invisible part of the scenegraph.
7698  *
7699  * Also be aware that painting is a NOP for actors with an opacity of
7700  * 0
7701  *
7702  * When you are implementing a custom actor you must queue a redraw
7703  * whenever some private state changes that will affect painting or
7704  * picking of your actor.
7705  */
7706 void
7707 clutter_actor_queue_redraw (ClutterActor *self)
7708 {
7709   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7710
7711   _clutter_actor_queue_redraw_full (self,
7712                                     0, /* flags */
7713                                     NULL, /* clip volume */
7714                                     NULL /* effect */);
7715 }
7716
7717 /*< private >
7718  * _clutter_actor_queue_redraw_with_clip:
7719  * @self: A #ClutterActor
7720  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7721  *   this queue redraw.
7722  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7723  *   redrawn or %NULL if you are just using a @flag to state your
7724  *   desired clipping.
7725  *
7726  * Queues up a clipped redraw of an actor and any children. The redraw
7727  * occurs once the main loop becomes idle (after the current batch of
7728  * events has been processed, roughly).
7729  *
7730  * If no flags are given the clip volume is defined by @volume
7731  * specified in actor coordinates and tells Clutter that only content
7732  * within this volume has been changed so Clutter can optionally
7733  * optimize the redraw.
7734  *
7735  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7736  * should be %NULL and this tells Clutter to use the actor's current
7737  * allocation as a clip box. This flag can only be used for 2D actors,
7738  * because any actor with depth may be projected outside its
7739  * allocation.
7740  *
7741  * Applications rarely need to call this, as redraws are handled
7742  * automatically by modification functions.
7743  *
7744  * This function will not do anything if @self is not visible, or if
7745  * the actor is inside an invisible part of the scenegraph.
7746  *
7747  * Also be aware that painting is a NOP for actors with an opacity of
7748  * 0
7749  *
7750  * When you are implementing a custom actor you must queue a redraw
7751  * whenever some private state changes that will affect painting or
7752  * picking of your actor.
7753  */
7754 void
7755 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7756                                        ClutterRedrawFlags  flags,
7757                                        ClutterPaintVolume *volume)
7758 {
7759   _clutter_actor_queue_redraw_full (self,
7760                                     flags, /* flags */
7761                                     volume, /* clip volume */
7762                                     NULL /* effect */);
7763 }
7764
7765 static void
7766 _clutter_actor_queue_only_relayout (ClutterActor *self)
7767 {
7768   ClutterActorPrivate *priv = self->priv;
7769
7770   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7771     return;
7772
7773   if (priv->needs_width_request &&
7774       priv->needs_height_request &&
7775       priv->needs_allocation)
7776     return; /* save some cpu cycles */
7777
7778 #if CLUTTER_ENABLE_DEBUG
7779   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7780     {
7781       g_warning ("The actor '%s' is currently inside an allocation "
7782                  "cycle; calling clutter_actor_queue_relayout() is "
7783                  "not recommended",
7784                  _clutter_actor_get_debug_name (self));
7785     }
7786 #endif /* CLUTTER_ENABLE_DEBUG */
7787
7788   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7789 }
7790
7791 /**
7792  * clutter_actor_queue_redraw_with_clip:
7793  * @self: a #ClutterActor
7794  * @clip: (allow-none): a rectangular clip region, or %NULL
7795  *
7796  * Queues a redraw on @self limited to a specific, actor-relative
7797  * rectangular area.
7798  *
7799  * If @clip is %NULL this function is equivalent to
7800  * clutter_actor_queue_redraw().
7801  *
7802  * Since: 1.10
7803  */
7804 void
7805 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7806                                       const cairo_rectangle_int_t *clip)
7807 {
7808   ClutterPaintVolume volume;
7809   ClutterVertex origin;
7810
7811   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7812
7813   if (clip == NULL)
7814     {
7815       clutter_actor_queue_redraw (self);
7816       return;
7817     }
7818
7819   _clutter_paint_volume_init_static (&volume, self);
7820
7821   origin.x = clip->x;
7822   origin.y = clip->y;
7823   origin.z = 0.0f;
7824
7825   clutter_paint_volume_set_origin (&volume, &origin);
7826   clutter_paint_volume_set_width (&volume, clip->width);
7827   clutter_paint_volume_set_height (&volume, clip->height);
7828
7829   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7830
7831   clutter_paint_volume_free (&volume);
7832 }
7833
7834 /**
7835  * clutter_actor_queue_relayout:
7836  * @self: A #ClutterActor
7837  *
7838  * Indicates that the actor's size request or other layout-affecting
7839  * properties may have changed. This function is used inside #ClutterActor
7840  * subclass implementations, not by applications directly.
7841  *
7842  * Queueing a new layout automatically queues a redraw as well.
7843  *
7844  * Since: 0.8
7845  */
7846 void
7847 clutter_actor_queue_relayout (ClutterActor *self)
7848 {
7849   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7850
7851   _clutter_actor_queue_only_relayout (self);
7852   clutter_actor_queue_redraw (self);
7853 }
7854
7855 /**
7856  * clutter_actor_get_preferred_size:
7857  * @self: a #ClutterActor
7858  * @min_width_p: (out) (allow-none): return location for the minimum
7859  *   width, or %NULL
7860  * @min_height_p: (out) (allow-none): return location for the minimum
7861  *   height, or %NULL
7862  * @natural_width_p: (out) (allow-none): return location for the natural
7863  *   width, or %NULL
7864  * @natural_height_p: (out) (allow-none): return location for the natural
7865  *   height, or %NULL
7866  *
7867  * Computes the preferred minimum and natural size of an actor, taking into
7868  * account the actor's geometry management (either height-for-width
7869  * or width-for-height).
7870  *
7871  * The width and height used to compute the preferred height and preferred
7872  * width are the actor's natural ones.
7873  *
7874  * If you need to control the height for the preferred width, or the width for
7875  * the preferred height, you should use clutter_actor_get_preferred_width()
7876  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7877  * geometry management using the #ClutterActor:request-mode property.
7878  *
7879  * Since: 0.8
7880  */
7881 void
7882 clutter_actor_get_preferred_size (ClutterActor *self,
7883                                   gfloat       *min_width_p,
7884                                   gfloat       *min_height_p,
7885                                   gfloat       *natural_width_p,
7886                                   gfloat       *natural_height_p)
7887 {
7888   ClutterActorPrivate *priv;
7889   gfloat min_width, min_height;
7890   gfloat natural_width, natural_height;
7891
7892   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7893
7894   priv = self->priv;
7895
7896   min_width = min_height = 0;
7897   natural_width = natural_height = 0;
7898
7899   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7900     {
7901       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7902       clutter_actor_get_preferred_width (self, -1,
7903                                          &min_width,
7904                                          &natural_width);
7905       clutter_actor_get_preferred_height (self, natural_width,
7906                                           &min_height,
7907                                           &natural_height);
7908     }
7909   else
7910     {
7911       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7912       clutter_actor_get_preferred_height (self, -1,
7913                                           &min_height,
7914                                           &natural_height);
7915       clutter_actor_get_preferred_width (self, natural_height,
7916                                          &min_width,
7917                                          &natural_width);
7918     }
7919
7920   if (min_width_p)
7921     *min_width_p = min_width;
7922
7923   if (min_height_p)
7924     *min_height_p = min_height;
7925
7926   if (natural_width_p)
7927     *natural_width_p = natural_width;
7928
7929   if (natural_height_p)
7930     *natural_height_p = natural_height;
7931 }
7932
7933 /*< private >
7934  * effective_align:
7935  * @align: a #ClutterActorAlign
7936  * @direction: a #ClutterTextDirection
7937  *
7938  * Retrieves the correct alignment depending on the text direction
7939  *
7940  * Return value: the effective alignment
7941  */
7942 static ClutterActorAlign
7943 effective_align (ClutterActorAlign    align,
7944                  ClutterTextDirection direction)
7945 {
7946   ClutterActorAlign res;
7947
7948   switch (align)
7949     {
7950     case CLUTTER_ACTOR_ALIGN_START:
7951       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7952           ? CLUTTER_ACTOR_ALIGN_END
7953           : CLUTTER_ACTOR_ALIGN_START;
7954       break;
7955
7956     case CLUTTER_ACTOR_ALIGN_END:
7957       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7958           ? CLUTTER_ACTOR_ALIGN_START
7959           : CLUTTER_ACTOR_ALIGN_END;
7960       break;
7961
7962     default:
7963       res = align;
7964       break;
7965     }
7966
7967   return res;
7968 }
7969
7970 /*< private >
7971  * _clutter_actor_get_effective_x_align:
7972  * @self: a #ClutterActor
7973  *
7974  * Retrieves the effective horizontal alignment, taking into
7975  * consideration the text direction of @self.
7976  *
7977  * Return value: the effective horizontal alignment
7978  */
7979 ClutterActorAlign
7980 _clutter_actor_get_effective_x_align (ClutterActor *self)
7981 {
7982   return effective_align (clutter_actor_get_x_align (self),
7983                           clutter_actor_get_text_direction (self));
7984 }
7985
7986 static inline void
7987 adjust_for_margin (float  margin_start,
7988                    float  margin_end,
7989                    float *minimum_size,
7990                    float *natural_size,
7991                    float *allocated_start,
7992                    float *allocated_end)
7993 {
7994   *minimum_size -= (margin_start + margin_end);
7995   *natural_size -= (margin_start + margin_end);
7996   *allocated_start += margin_start;
7997   *allocated_end -= margin_end;
7998 }
7999
8000 static inline void
8001 adjust_for_alignment (ClutterActorAlign  alignment,
8002                       float              natural_size,
8003                       float             *allocated_start,
8004                       float             *allocated_end)
8005 {
8006   float allocated_size = *allocated_end - *allocated_start;
8007
8008   switch (alignment)
8009     {
8010     case CLUTTER_ACTOR_ALIGN_FILL:
8011       /* do nothing */
8012       break;
8013
8014     case CLUTTER_ACTOR_ALIGN_START:
8015       /* keep start */
8016       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
8017       break;
8018
8019     case CLUTTER_ACTOR_ALIGN_END:
8020       if (allocated_size > natural_size)
8021         {
8022           *allocated_start += (allocated_size - natural_size);
8023           *allocated_end = *allocated_start + natural_size;
8024         }
8025       break;
8026
8027     case CLUTTER_ACTOR_ALIGN_CENTER:
8028       if (allocated_size > natural_size)
8029         {
8030           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
8031           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
8032         }
8033       break;
8034     }
8035 }
8036
8037 /*< private >
8038  * clutter_actor_adjust_width:
8039  * @self: a #ClutterActor
8040  * @minimum_width: (inout): the actor's preferred minimum width, which
8041  *   will be adjusted depending on the margin
8042  * @natural_width: (inout): the actor's preferred natural width, which
8043  *   will be adjusted depending on the margin
8044  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
8045  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
8046  *
8047  * Adjusts the preferred and allocated position and size of an actor,
8048  * depending on the margin and alignment properties.
8049  */
8050 static void
8051 clutter_actor_adjust_width (ClutterActor *self,
8052                             gfloat       *minimum_width,
8053                             gfloat       *natural_width,
8054                             gfloat       *adjusted_x1,
8055                             gfloat       *adjusted_x2)
8056 {
8057   ClutterTextDirection text_dir;
8058   const ClutterLayoutInfo *info;
8059
8060   info = _clutter_actor_get_layout_info_or_defaults (self);
8061   text_dir = clutter_actor_get_text_direction (self);
8062
8063   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
8064
8065   /* this will tweak natural_width to remove the margin, so that
8066    * adjust_for_alignment() will use the correct size
8067    */
8068   adjust_for_margin (info->margin.left, info->margin.right,
8069                      minimum_width, natural_width,
8070                      adjusted_x1, adjusted_x2);
8071
8072   adjust_for_alignment (effective_align (info->x_align, text_dir),
8073                         *natural_width,
8074                         adjusted_x1, adjusted_x2);
8075 }
8076
8077 /*< private >
8078  * clutter_actor_adjust_height:
8079  * @self: a #ClutterActor
8080  * @minimum_height: (inout): the actor's preferred minimum height, which
8081  *   will be adjusted depending on the margin
8082  * @natural_height: (inout): the actor's preferred natural height, which
8083  *   will be adjusted depending on the margin
8084  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
8085  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
8086  *
8087  * Adjusts the preferred and allocated position and size of an actor,
8088  * depending on the margin and alignment properties.
8089  */
8090 static void
8091 clutter_actor_adjust_height (ClutterActor *self,
8092                              gfloat       *minimum_height,
8093                              gfloat       *natural_height,
8094                              gfloat       *adjusted_y1,
8095                              gfloat       *adjusted_y2)
8096 {
8097   const ClutterLayoutInfo *info;
8098
8099   info = _clutter_actor_get_layout_info_or_defaults (self);
8100
8101   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
8102
8103   /* this will tweak natural_height to remove the margin, so that
8104    * adjust_for_alignment() will use the correct size
8105    */
8106   adjust_for_margin (info->margin.top, info->margin.bottom,
8107                      minimum_height, natural_height,
8108                      adjusted_y1,
8109                      adjusted_y2);
8110
8111   /* we don't use effective_align() here, because text direction
8112    * only affects the horizontal axis
8113    */
8114   adjust_for_alignment (info->y_align,
8115                         *natural_height,
8116                         adjusted_y1,
8117                         adjusted_y2);
8118
8119 }
8120
8121 /* looks for a cached size request for this for_size. If not
8122  * found, returns the oldest entry so it can be overwritten */
8123 static gboolean
8124 _clutter_actor_get_cached_size_request (gfloat         for_size,
8125                                         SizeRequest   *cached_size_requests,
8126                                         SizeRequest  **result)
8127 {
8128   guint i;
8129
8130   *result = &cached_size_requests[0];
8131
8132   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
8133     {
8134       SizeRequest *sr;
8135
8136       sr = &cached_size_requests[i];
8137
8138       if (sr->age > 0 &&
8139           sr->for_size == for_size)
8140         {
8141           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8142           *result = sr;
8143           return TRUE;
8144         }
8145       else if (sr->age < (*result)->age)
8146         {
8147           *result = sr;
8148         }
8149     }
8150
8151   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8152
8153   return FALSE;
8154 }
8155
8156 /**
8157  * clutter_actor_get_preferred_width:
8158  * @self: A #ClutterActor
8159  * @for_height: available height when computing the preferred width,
8160  *   or a negative value to indicate that no height is defined
8161  * @min_width_p: (out) (allow-none): return location for minimum width,
8162  *   or %NULL
8163  * @natural_width_p: (out) (allow-none): return location for the natural
8164  *   width, or %NULL
8165  *
8166  * Computes the requested minimum and natural widths for an actor,
8167  * optionally depending on the specified height, or if they are
8168  * already computed, returns the cached values.
8169  *
8170  * An actor may not get its request - depending on the layout
8171  * manager that's in effect.
8172  *
8173  * A request should not incorporate the actor's scale or anchor point;
8174  * those transformations do not affect layout, only rendering.
8175  *
8176  * Since: 0.8
8177  */
8178 void
8179 clutter_actor_get_preferred_width (ClutterActor *self,
8180                                    gfloat        for_height,
8181                                    gfloat       *min_width_p,
8182                                    gfloat       *natural_width_p)
8183 {
8184   float request_min_width, request_natural_width;
8185   SizeRequest *cached_size_request;
8186   const ClutterLayoutInfo *info;
8187   ClutterActorPrivate *priv;
8188   gboolean found_in_cache;
8189
8190   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8191
8192   priv = self->priv;
8193
8194   info = _clutter_actor_get_layout_info_or_defaults (self);
8195
8196   /* we shortcircuit the case of a fixed size set using set_width() */
8197   if (priv->min_width_set && priv->natural_width_set)
8198     {
8199       if (min_width_p != NULL)
8200         *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8201
8202       if (natural_width_p != NULL)
8203         *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8204
8205       return;
8206     }
8207
8208   /* the remaining cases are:
8209    *
8210    *   - either min_width or natural_width have been set
8211    *   - neither min_width or natural_width have been set
8212    *
8213    * in both cases, we go through the cache (and through the actor in case
8214    * of cache misses) and determine the authoritative value depending on
8215    * the *_set flags.
8216    */
8217
8218   if (!priv->needs_width_request)
8219     {
8220       found_in_cache =
8221         _clutter_actor_get_cached_size_request (for_height,
8222                                                 priv->width_requests,
8223                                                 &cached_size_request);
8224     }
8225   else
8226     {
8227       /* if the actor needs a width request we use the first slot */
8228       found_in_cache = FALSE;
8229       cached_size_request = &priv->width_requests[0];
8230     }
8231
8232   if (!found_in_cache)
8233     {
8234       gfloat minimum_width, natural_width;
8235       ClutterActorClass *klass;
8236
8237       minimum_width = natural_width = 0;
8238
8239       /* adjust for the margin */
8240       if (for_height >= 0)
8241         {
8242           for_height -= (info->margin.top + info->margin.bottom);
8243           if (for_height < 0)
8244             for_height = 0;
8245         }
8246
8247       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8248
8249       klass = CLUTTER_ACTOR_GET_CLASS (self);
8250       klass->get_preferred_width (self, for_height,
8251                                   &minimum_width,
8252                                   &natural_width);
8253
8254       /* adjust for the margin */
8255       minimum_width += (info->margin.left + info->margin.right);
8256       natural_width += (info->margin.left + info->margin.right);
8257
8258       /* Due to accumulated float errors, it's better not to warn
8259        * on this, but just fix it.
8260        */
8261       if (natural_width < minimum_width)
8262         natural_width = minimum_width;
8263
8264       cached_size_request->min_size = minimum_width;
8265       cached_size_request->natural_size = natural_width;
8266       cached_size_request->for_size = for_height;
8267       cached_size_request->age = priv->cached_width_age;
8268
8269       priv->cached_width_age += 1;
8270       priv->needs_width_request = FALSE;
8271     }
8272
8273   if (!priv->min_width_set)
8274     request_min_width = cached_size_request->min_size;
8275   else
8276     request_min_width = info->margin.left
8277                       + info->minimum.width
8278                       + info->margin.right;
8279
8280   if (!priv->natural_width_set)
8281     request_natural_width = cached_size_request->natural_size;
8282   else
8283     request_natural_width = info->margin.left
8284                           + info->natural.width
8285                           + info->margin.right;
8286
8287   if (min_width_p)
8288     *min_width_p = request_min_width;
8289
8290   if (natural_width_p)
8291     *natural_width_p = request_natural_width;
8292 }
8293
8294 /**
8295  * clutter_actor_get_preferred_height:
8296  * @self: A #ClutterActor
8297  * @for_width: available width to assume in computing desired height,
8298  *   or a negative value to indicate that no width is defined
8299  * @min_height_p: (out) (allow-none): return location for minimum height,
8300  *   or %NULL
8301  * @natural_height_p: (out) (allow-none): return location for natural
8302  *   height, or %NULL
8303  *
8304  * Computes the requested minimum and natural heights for an actor,
8305  * or if they are already computed, returns the cached values.
8306  *
8307  * An actor may not get its request - depending on the layout
8308  * manager that's in effect.
8309  *
8310  * A request should not incorporate the actor's scale or anchor point;
8311  * those transformations do not affect layout, only rendering.
8312  *
8313  * Since: 0.8
8314  */
8315 void
8316 clutter_actor_get_preferred_height (ClutterActor *self,
8317                                     gfloat        for_width,
8318                                     gfloat       *min_height_p,
8319                                     gfloat       *natural_height_p)
8320 {
8321   float request_min_height, request_natural_height;
8322   SizeRequest *cached_size_request;
8323   const ClutterLayoutInfo *info;
8324   ClutterActorPrivate *priv;
8325   gboolean found_in_cache;
8326
8327   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8328
8329   priv = self->priv;
8330
8331   info = _clutter_actor_get_layout_info_or_defaults (self);
8332
8333   /* we shortcircuit the case of a fixed size set using set_height() */
8334   if (priv->min_height_set && priv->natural_height_set)
8335     {
8336       if (min_height_p != NULL)
8337         *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8338
8339       if (natural_height_p != NULL)
8340         *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8341
8342       return;
8343     }
8344
8345   /* the remaining cases are:
8346    *
8347    *   - either min_height or natural_height have been set
8348    *   - neither min_height or natural_height have been set
8349    *
8350    * in both cases, we go through the cache (and through the actor in case
8351    * of cache misses) and determine the authoritative value depending on
8352    * the *_set flags.
8353    */
8354
8355   if (!priv->needs_height_request)
8356     {
8357       found_in_cache =
8358         _clutter_actor_get_cached_size_request (for_width,
8359                                                 priv->height_requests,
8360                                                 &cached_size_request);
8361     }
8362   else
8363     {
8364       found_in_cache = FALSE;
8365       cached_size_request = &priv->height_requests[0];
8366     }
8367
8368   if (!found_in_cache)
8369     {
8370       gfloat minimum_height, natural_height;
8371       ClutterActorClass *klass;
8372
8373       minimum_height = natural_height = 0;
8374
8375       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8376
8377       /* adjust for margin */
8378       if (for_width >= 0)
8379         {
8380           for_width -= (info->margin.left + info->margin.right);
8381           if (for_width < 0)
8382             for_width = 0;
8383         }
8384
8385       klass = CLUTTER_ACTOR_GET_CLASS (self);
8386       klass->get_preferred_height (self, for_width,
8387                                    &minimum_height,
8388                                    &natural_height);
8389
8390       /* adjust for margin */
8391       minimum_height += (info->margin.top + info->margin.bottom);
8392       natural_height += (info->margin.top + info->margin.bottom);
8393
8394       /* Due to accumulated float errors, it's better not to warn
8395        * on this, but just fix it.
8396        */
8397       if (natural_height < minimum_height)
8398         natural_height = minimum_height;
8399
8400       cached_size_request->min_size = minimum_height;
8401       cached_size_request->natural_size = natural_height;
8402       cached_size_request->for_size = for_width;
8403       cached_size_request->age = priv->cached_height_age;
8404
8405       priv->cached_height_age += 1;
8406       priv->needs_height_request = FALSE;
8407     }
8408
8409   if (!priv->min_height_set)
8410     request_min_height = cached_size_request->min_size;
8411   else
8412     request_min_height = info->margin.top
8413                        + info->minimum.height
8414                        + info->margin.bottom;
8415
8416   if (!priv->natural_height_set)
8417     request_natural_height = cached_size_request->natural_size;
8418   else
8419     request_natural_height = info->margin.top
8420                            + info->natural.height
8421                            + info->margin.bottom;
8422
8423   if (min_height_p)
8424     *min_height_p = request_min_height;
8425
8426   if (natural_height_p)
8427     *natural_height_p = request_natural_height;
8428 }
8429
8430 /**
8431  * clutter_actor_get_allocation_box:
8432  * @self: A #ClutterActor
8433  * @box: (out): the function fills this in with the actor's allocation
8434  *
8435  * Gets the layout box an actor has been assigned. The allocation can
8436  * only be assumed valid inside a paint() method; anywhere else, it
8437  * may be out-of-date.
8438  *
8439  * An allocation does not incorporate the actor's scale or anchor point;
8440  * those transformations do not affect layout, only rendering.
8441  *
8442  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8443  * of functions inside the implementation of the get_preferred_width()
8444  * or get_preferred_height() virtual functions.</note>
8445  *
8446  * Since: 0.8
8447  */
8448 void
8449 clutter_actor_get_allocation_box (ClutterActor    *self,
8450                                   ClutterActorBox *box)
8451 {
8452   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8453
8454   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8455    * which limits calling get_allocation to inside paint() basically; or
8456    * we can 2) force a layout, which could be expensive if someone calls
8457    * get_allocation somewhere silly; or we can 3) just return the latest
8458    * value, allowing it to be out-of-date, and assume people know what
8459    * they are doing.
8460    *
8461    * The least-surprises approach that keeps existing code working is
8462    * likely to be 2). People can end up doing some inefficient things,
8463    * though, and in general code that requires 2) is probably broken.
8464    */
8465
8466   /* this implements 2) */
8467   if (G_UNLIKELY (self->priv->needs_allocation))
8468     {
8469       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8470
8471       /* do not queue a relayout on an unparented actor */
8472       if (stage)
8473         _clutter_stage_maybe_relayout (stage);
8474     }
8475
8476   /* commenting out the code above and just keeping this assigment
8477    * implements 3)
8478    */
8479   *box = self->priv->allocation;
8480 }
8481
8482 /**
8483  * clutter_actor_get_allocation_geometry:
8484  * @self: A #ClutterActor
8485  * @geom: (out): allocation geometry in pixels
8486  *
8487  * Gets the layout box an actor has been assigned.  The allocation can
8488  * only be assumed valid inside a paint() method; anywhere else, it
8489  * may be out-of-date.
8490  *
8491  * An allocation does not incorporate the actor's scale or anchor point;
8492  * those transformations do not affect layout, only rendering.
8493  *
8494  * The returned rectangle is in pixels.
8495  *
8496  * Since: 0.8
8497  */
8498 void
8499 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8500                                        ClutterGeometry *geom)
8501 {
8502   ClutterActorBox box;
8503
8504   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8505   g_return_if_fail (geom != NULL);
8506
8507   clutter_actor_get_allocation_box (self, &box);
8508
8509   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8510   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8511   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8512   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8513 }
8514
8515 static void
8516 clutter_actor_update_constraints (ClutterActor    *self,
8517                                   ClutterActorBox *allocation)
8518 {
8519   ClutterActorPrivate *priv = self->priv;
8520   const GList *constraints, *l;
8521
8522   if (priv->constraints == NULL)
8523     return;
8524
8525   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8526   for (l = constraints; l != NULL; l = l->next)
8527     {
8528       ClutterConstraint *constraint = l->data;
8529       ClutterActorMeta *meta = l->data;
8530
8531       if (clutter_actor_meta_get_enabled (meta))
8532         {
8533           _clutter_constraint_update_allocation (constraint,
8534                                                  self,
8535                                                  allocation);
8536
8537           CLUTTER_NOTE (LAYOUT,
8538                         "Allocation of '%s' after constraint '%s': "
8539                         "{ %.2f, %.2f, %.2f, %.2f }",
8540                         _clutter_actor_get_debug_name (self),
8541                         _clutter_actor_meta_get_debug_name (meta),
8542                         allocation->x1,
8543                         allocation->y1,
8544                         allocation->x2,
8545                         allocation->y2);
8546         }
8547     }
8548 }
8549
8550 /*< private >
8551  * clutter_actor_adjust_allocation:
8552  * @self: a #ClutterActor
8553  * @allocation: (inout): the allocation to adjust
8554  *
8555  * Adjusts the passed allocation box taking into account the actor's
8556  * layout information, like alignment, expansion, and margin.
8557  */
8558 static void
8559 clutter_actor_adjust_allocation (ClutterActor    *self,
8560                                  ClutterActorBox *allocation)
8561 {
8562   ClutterActorBox adj_allocation;
8563   float alloc_width, alloc_height;
8564   float min_width, min_height;
8565   float nat_width, nat_height;
8566   ClutterRequestMode req_mode;
8567
8568   adj_allocation = *allocation;
8569
8570   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8571
8572   /* we want to hit the cache, so we use the public API */
8573   req_mode = clutter_actor_get_request_mode (self);
8574
8575   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8576     {
8577       clutter_actor_get_preferred_width (self, -1,
8578                                          &min_width,
8579                                          &nat_width);
8580       clutter_actor_get_preferred_height (self, alloc_width,
8581                                           &min_height,
8582                                           &nat_height);
8583     }
8584   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8585     {
8586       clutter_actor_get_preferred_height (self, -1,
8587                                           &min_height,
8588                                           &nat_height);
8589       clutter_actor_get_preferred_height (self, alloc_height,
8590                                           &min_width,
8591                                           &nat_width);
8592     }
8593
8594 #ifdef CLUTTER_ENABLE_DEBUG
8595   /* warn about underallocations */
8596   if (_clutter_diagnostic_enabled () &&
8597       (floorf (min_width - alloc_width) > 0 ||
8598        floorf (min_height - alloc_height) > 0))
8599     {
8600       ClutterActor *parent = clutter_actor_get_parent (self);
8601
8602       /* the only actors that are allowed to be underallocated are the Stage,
8603        * as it doesn't have an implicit size, and Actors that specifically
8604        * told us that they want to opt-out from layout control mechanisms
8605        * through the NO_LAYOUT escape hatch.
8606        */
8607       if (parent != NULL &&
8608           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8609         {
8610           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8611                      "of %.2f x %.2f from its parent actor '%s', but its "
8612                      "requested minimum size is of %.2f x %.2f",
8613                      _clutter_actor_get_debug_name (self),
8614                      alloc_width, alloc_height,
8615                      _clutter_actor_get_debug_name (parent),
8616                      min_width, min_height);
8617         }
8618     }
8619 #endif
8620
8621   clutter_actor_adjust_width (self,
8622                               &min_width,
8623                               &nat_width,
8624                               &adj_allocation.x1,
8625                               &adj_allocation.x2);
8626
8627   clutter_actor_adjust_height (self,
8628                                &min_height,
8629                                &nat_height,
8630                                &adj_allocation.y1,
8631                                &adj_allocation.y2);
8632
8633   /* we maintain the invariant that an allocation cannot be adjusted
8634    * to be outside the parent-given box
8635    */
8636   if (adj_allocation.x1 < allocation->x1 ||
8637       adj_allocation.y1 < allocation->y1 ||
8638       adj_allocation.x2 > allocation->x2 ||
8639       adj_allocation.y2 > allocation->y2)
8640     {
8641       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8642                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8643                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8644                  _clutter_actor_get_debug_name (self),
8645                  adj_allocation.x1, adj_allocation.y1,
8646                  adj_allocation.x2 - adj_allocation.x1,
8647                  adj_allocation.y2 - adj_allocation.y1,
8648                  allocation->x1, allocation->y1,
8649                  allocation->x2 - allocation->x1,
8650                  allocation->y2 - allocation->y1);
8651       return;
8652     }
8653
8654   *allocation = adj_allocation;
8655 }
8656
8657 static void
8658 clutter_actor_allocate_internal (ClutterActor           *self,
8659                                  const ClutterActorBox  *allocation,
8660                                  ClutterAllocationFlags  flags)
8661 {
8662   ClutterActorClass *klass;
8663
8664   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8665
8666   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8667                 _clutter_actor_get_debug_name (self));
8668
8669   klass = CLUTTER_ACTOR_GET_CLASS (self);
8670   klass->allocate (self, allocation, flags);
8671
8672   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8673
8674   clutter_actor_queue_redraw (self);
8675 }
8676
8677 /**
8678  * clutter_actor_allocate:
8679  * @self: A #ClutterActor
8680  * @box: new allocation of the actor, in parent-relative coordinates
8681  * @flags: flags that control the allocation
8682  *
8683  * Called by the parent of an actor to assign the actor its size.
8684  * Should never be called by applications (except when implementing
8685  * a container or layout manager).
8686  *
8687  * Actors can know from their allocation box whether they have moved
8688  * with respect to their parent actor. The @flags parameter describes
8689  * additional information about the allocation, for instance whether
8690  * the parent has moved with respect to the stage, for example because
8691  * a grandparent's origin has moved.
8692  *
8693  * Since: 0.8
8694  */
8695 void
8696 clutter_actor_allocate (ClutterActor           *self,
8697                         const ClutterActorBox  *box,
8698                         ClutterAllocationFlags  flags)
8699 {
8700   ClutterActorBox old_allocation, real_allocation;
8701   gboolean origin_changed, child_moved, size_changed;
8702   gboolean stage_allocation_changed;
8703   ClutterActorPrivate *priv;
8704
8705   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8706   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8707     {
8708       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8709                  "which isn't a descendent of the stage!\n",
8710                  self, _clutter_actor_get_debug_name (self));
8711       return;
8712     }
8713
8714   priv = self->priv;
8715
8716   old_allocation = priv->allocation;
8717   real_allocation = *box;
8718
8719   /* constraints are allowed to modify the allocation only here; we do
8720    * this prior to all the other checks so that we can bail out if the
8721    * allocation did not change
8722    */
8723   clutter_actor_update_constraints (self, &real_allocation);
8724
8725   /* adjust the allocation depending on the align/margin properties */
8726   clutter_actor_adjust_allocation (self, &real_allocation);
8727
8728   if (real_allocation.x2 < real_allocation.x1 ||
8729       real_allocation.y2 < real_allocation.y1)
8730     {
8731       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8732                  _clutter_actor_get_debug_name (self),
8733                  real_allocation.x2 - real_allocation.x1,
8734                  real_allocation.y2 - real_allocation.y1);
8735     }
8736
8737   /* we allow 0-sized actors, but not negative-sized ones */
8738   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8739   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8740
8741   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8742
8743   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8744                  real_allocation.y1 != old_allocation.y1);
8745
8746   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8747                   real_allocation.y2 != old_allocation.y2);
8748
8749   if (origin_changed || child_moved || size_changed)
8750     stage_allocation_changed = TRUE;
8751   else
8752     stage_allocation_changed = FALSE;
8753
8754   /* If we get an allocation "out of the blue"
8755    * (we did not queue relayout), then we want to
8756    * ignore it. But if we have needs_allocation set,
8757    * we want to guarantee that allocate() virtual
8758    * method is always called, i.e. that queue_relayout()
8759    * always results in an allocate() invocation on
8760    * an actor.
8761    *
8762    * The optimization here is to avoid re-allocating
8763    * actors that did not queue relayout and were
8764    * not moved.
8765    */
8766   if (!priv->needs_allocation && !stage_allocation_changed)
8767     {
8768       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8769       return;
8770     }
8771
8772   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8773    * clutter_actor_allocate(), it indicates whether the parent has its
8774    * absolute origin moved; when passed in to ClutterActor::allocate()
8775    * virtual method though, it indicates whether the child has its
8776    * absolute origin moved.  So we set it when child_moved is TRUE
8777    */
8778   if (child_moved)
8779     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8780
8781   /* store the flags here, so that they can be propagated by the
8782    * transition code
8783    */
8784   self->priv->allocation_flags = flags;
8785
8786   if (_clutter_actor_get_transition (self, obj_props[PROP_ALLOCATION]) == NULL)
8787     {
8788       _clutter_actor_create_transition (self, obj_props[PROP_ALLOCATION],
8789                                         &priv->allocation,
8790                                         &real_allocation);
8791     }
8792   else
8793     _clutter_actor_update_transition (self, obj_props[PROP_ALLOCATION],
8794                                       &real_allocation);
8795 }
8796
8797 /**
8798  * clutter_actor_set_allocation:
8799  * @self: a #ClutterActor
8800  * @box: a #ClutterActorBox
8801  * @flags: allocation flags
8802  *
8803  * Stores the allocation of @self as defined by @box.
8804  *
8805  * This function can only be called from within the implementation of
8806  * the #ClutterActorClass.allocate() virtual function.
8807  *
8808  * The allocation should have been adjusted to take into account constraints,
8809  * alignment, and margin properties. If you are implementing a #ClutterActor
8810  * subclass that provides its own layout management policy for its children
8811  * instead of using a #ClutterLayoutManager delegate, you should not call
8812  * this function on the children of @self; instead, you should call
8813  * clutter_actor_allocate(), which will adjust the allocation box for
8814  * you.
8815  *
8816  * This function should only be used by subclasses of #ClutterActor
8817  * that wish to store their allocation but cannot chain up to the
8818  * parent's implementation; the default implementation of the
8819  * #ClutterActorClass.allocate() virtual function will call this
8820  * function.
8821  *
8822  * It is important to note that, while chaining up was the recommended
8823  * behaviour for #ClutterActor subclasses prior to the introduction of
8824  * this function, it is recommended to call clutter_actor_set_allocation()
8825  * instead.
8826  *
8827  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8828  * to handle the allocation of its children, this function will call
8829  * the clutter_layout_manager_allocate() function only if the
8830  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8831  * expected that the subclass will call clutter_layout_manager_allocate()
8832  * by itself. For instance, the following code:
8833  *
8834  * |[
8835  * static void
8836  * my_actor_allocate (ClutterActor *actor,
8837  *                    const ClutterActorBox *allocation,
8838  *                    ClutterAllocationFlags flags)
8839  * {
8840  *   ClutterActorBox new_alloc;
8841  *   ClutterAllocationFlags new_flags;
8842  *
8843  *   adjust_allocation (allocation, &amp;new_alloc);
8844  *
8845  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8846  *
8847  *   /&ast; this will use the layout manager set on the actor &ast;/
8848  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8849  * }
8850  * ]|
8851  *
8852  * is equivalent to this:
8853  *
8854  * |[
8855  * static void
8856  * my_actor_allocate (ClutterActor *actor,
8857  *                    const ClutterActorBox *allocation,
8858  *                    ClutterAllocationFlags flags)
8859  * {
8860  *   ClutterLayoutManager *layout;
8861  *   ClutterActorBox new_alloc;
8862  *
8863  *   adjust_allocation (allocation, &amp;new_alloc);
8864  *
8865  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8866  *
8867  *   layout = clutter_actor_get_layout_manager (actor);
8868  *   clutter_layout_manager_allocate (layout,
8869  *                                    CLUTTER_CONTAINER (actor),
8870  *                                    &amp;new_alloc,
8871  *                                    flags);
8872  * }
8873  * ]|
8874  *
8875  * Since: 1.10
8876  */
8877 void
8878 clutter_actor_set_allocation (ClutterActor           *self,
8879                               const ClutterActorBox  *box,
8880                               ClutterAllocationFlags  flags)
8881 {
8882   ClutterActorPrivate *priv;
8883   gboolean changed;
8884
8885   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8886   g_return_if_fail (box != NULL);
8887
8888   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8889     {
8890       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8891                   "can only be called from within the implementation of "
8892                   "the ClutterActor::allocate() virtual function.");
8893       return;
8894     }
8895
8896   priv = self->priv;
8897
8898   g_object_freeze_notify (G_OBJECT (self));
8899
8900   changed = clutter_actor_set_allocation_internal (self, box, flags);
8901
8902   /* we allocate our children before we notify changes in our geometry,
8903    * so that people connecting to properties will be able to get valid
8904    * data out of the sub-tree of the scene graph that has this actor at
8905    * the root.
8906    */
8907   clutter_actor_maybe_layout_children (self, box, flags);
8908
8909   if (changed)
8910     {
8911       ClutterActorBox signal_box = priv->allocation;
8912       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8913
8914       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8915                      &signal_box,
8916                      signal_flags);
8917     }
8918
8919   g_object_thaw_notify (G_OBJECT (self));
8920 }
8921
8922 /**
8923  * clutter_actor_set_geometry:
8924  * @self: A #ClutterActor
8925  * @geometry: A #ClutterGeometry
8926  *
8927  * Sets the actor's fixed position and forces its minimum and natural
8928  * size, in pixels. This means the untransformed actor will have the
8929  * given geometry. This is the same as calling clutter_actor_set_position()
8930  * and clutter_actor_set_size().
8931  *
8932  * Deprecated: 1.10: Use clutter_actor_set_position() and
8933  *   clutter_actor_set_size() instead.
8934  */
8935 void
8936 clutter_actor_set_geometry (ClutterActor          *self,
8937                             const ClutterGeometry *geometry)
8938 {
8939   g_object_freeze_notify (G_OBJECT (self));
8940
8941   clutter_actor_set_position (self, geometry->x, geometry->y);
8942   clutter_actor_set_size (self, geometry->width, geometry->height);
8943
8944   g_object_thaw_notify (G_OBJECT (self));
8945 }
8946
8947 /**
8948  * clutter_actor_get_geometry:
8949  * @self: A #ClutterActor
8950  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8951  *
8952  * Gets the size and position of an actor relative to its parent
8953  * actor. This is the same as calling clutter_actor_get_position() and
8954  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8955  * requested size and position if the actor's allocation is invalid.
8956  *
8957  * Deprecated: 1.10: Use clutter_actor_get_position() and
8958  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8959  *   instead.
8960  */
8961 void
8962 clutter_actor_get_geometry (ClutterActor    *self,
8963                             ClutterGeometry *geometry)
8964 {
8965   gfloat x, y, width, height;
8966
8967   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8968   g_return_if_fail (geometry != NULL);
8969
8970   clutter_actor_get_position (self, &x, &y);
8971   clutter_actor_get_size (self, &width, &height);
8972
8973   geometry->x = (int) x;
8974   geometry->y = (int) y;
8975   geometry->width = (int) width;
8976   geometry->height = (int) height;
8977 }
8978
8979 /**
8980  * clutter_actor_set_position:
8981  * @self: A #ClutterActor
8982  * @x: New left position of actor in pixels.
8983  * @y: New top position of actor in pixels.
8984  *
8985  * Sets the actor's fixed position in pixels relative to any parent
8986  * actor.
8987  *
8988  * If a layout manager is in use, this position will override the
8989  * layout manager and force a fixed position.
8990  */
8991 void
8992 clutter_actor_set_position (ClutterActor *self,
8993                             gfloat        x,
8994                             gfloat        y)
8995 {
8996   ClutterPoint new_position;
8997
8998   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8999
9000   clutter_point_init (&new_position, x, y);
9001
9002   if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
9003     {
9004       ClutterPoint cur_position;
9005
9006       cur_position.x = clutter_actor_get_x (self);
9007       cur_position.y = clutter_actor_get_y (self);
9008
9009       _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
9010                                         &cur_position,
9011                                         &new_position);
9012     }
9013   else
9014     _clutter_actor_update_transition (self,
9015                                       obj_props[PROP_POSITION],
9016                                       &new_position);
9017
9018   clutter_actor_queue_relayout (self);
9019 }
9020
9021 /**
9022  * clutter_actor_get_fixed_position_set:
9023  * @self: A #ClutterActor
9024  *
9025  * Checks whether an actor has a fixed position set (and will thus be
9026  * unaffected by any layout manager).
9027  *
9028  * Return value: %TRUE if the fixed position is set on the actor
9029  *
9030  * Since: 0.8
9031  */
9032 gboolean
9033 clutter_actor_get_fixed_position_set (ClutterActor *self)
9034 {
9035   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9036
9037   return self->priv->position_set;
9038 }
9039
9040 /**
9041  * clutter_actor_set_fixed_position_set:
9042  * @self: A #ClutterActor
9043  * @is_set: whether to use fixed position
9044  *
9045  * Sets whether an actor has a fixed position set (and will thus be
9046  * unaffected by any layout manager).
9047  *
9048  * Since: 0.8
9049  */
9050 void
9051 clutter_actor_set_fixed_position_set (ClutterActor *self,
9052                                       gboolean      is_set)
9053 {
9054   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9055
9056   if (self->priv->position_set == (is_set != FALSE))
9057     return;
9058
9059   self->priv->position_set = is_set != FALSE;
9060   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
9061
9062   clutter_actor_queue_relayout (self);
9063 }
9064
9065 /**
9066  * clutter_actor_move_by:
9067  * @self: A #ClutterActor
9068  * @dx: Distance to move Actor on X axis.
9069  * @dy: Distance to move Actor on Y axis.
9070  *
9071  * Moves an actor by the specified distance relative to its current
9072  * position in pixels.
9073  *
9074  * This function modifies the fixed position of an actor and thus removes
9075  * it from any layout management. Another way to move an actor is with an
9076  * anchor point, see clutter_actor_set_anchor_point().
9077  *
9078  * Since: 0.2
9079  */
9080 void
9081 clutter_actor_move_by (ClutterActor *self,
9082                        gfloat        dx,
9083                        gfloat        dy)
9084 {
9085   const ClutterLayoutInfo *info;
9086   gfloat x, y;
9087
9088   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9089
9090   info = _clutter_actor_get_layout_info_or_defaults (self);
9091   x = info->fixed_pos.x;
9092   y = info->fixed_pos.y;
9093
9094   clutter_actor_set_position (self, x + dx, y + dy);
9095 }
9096
9097 static void
9098 clutter_actor_set_min_width (ClutterActor *self,
9099                              gfloat        min_width)
9100 {
9101   ClutterActorPrivate *priv = self->priv;
9102   ClutterActorBox old = { 0, };
9103   ClutterLayoutInfo *info;
9104
9105   /* if we are setting the size on a top-level actor and the
9106    * backend only supports static top-levels (e.g. framebuffers)
9107    * then we ignore the passed value and we override it with
9108    * the stage implementation's preferred size.
9109    */
9110   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9111       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9112     return;
9113
9114   info = _clutter_actor_get_layout_info (self);
9115
9116   if (priv->min_width_set && min_width == info->minimum.width)
9117     return;
9118
9119   g_object_freeze_notify (G_OBJECT (self));
9120
9121   clutter_actor_store_old_geometry (self, &old);
9122
9123   info->minimum.width = min_width;
9124   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
9125   clutter_actor_set_min_width_set (self, TRUE);
9126
9127   clutter_actor_notify_if_geometry_changed (self, &old);
9128
9129   g_object_thaw_notify (G_OBJECT (self));
9130
9131   clutter_actor_queue_relayout (self);
9132 }
9133
9134 static void
9135 clutter_actor_set_min_height (ClutterActor *self,
9136                               gfloat        min_height)
9137
9138 {
9139   ClutterActorPrivate *priv = self->priv;
9140   ClutterActorBox old = { 0, };
9141   ClutterLayoutInfo *info;
9142
9143   /* if we are setting the size on a top-level actor and the
9144    * backend only supports static top-levels (e.g. framebuffers)
9145    * then we ignore the passed value and we override it with
9146    * the stage implementation's preferred size.
9147    */
9148   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9149       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9150     return;
9151
9152   info = _clutter_actor_get_layout_info (self);
9153
9154   if (priv->min_height_set && min_height == info->minimum.height)
9155     return;
9156
9157   g_object_freeze_notify (G_OBJECT (self));
9158
9159   clutter_actor_store_old_geometry (self, &old);
9160
9161   info->minimum.height = min_height;
9162   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
9163   clutter_actor_set_min_height_set (self, TRUE);
9164
9165   clutter_actor_notify_if_geometry_changed (self, &old);
9166
9167   g_object_thaw_notify (G_OBJECT (self));
9168
9169   clutter_actor_queue_relayout (self);
9170 }
9171
9172 static void
9173 clutter_actor_set_natural_width (ClutterActor *self,
9174                                  gfloat        natural_width)
9175 {
9176   ClutterActorPrivate *priv = self->priv;
9177   ClutterActorBox old = { 0, };
9178   ClutterLayoutInfo *info;
9179
9180   /* if we are setting the size on a top-level actor and the
9181    * backend only supports static top-levels (e.g. framebuffers)
9182    * then we ignore the passed value and we override it with
9183    * the stage implementation's preferred size.
9184    */
9185   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9186       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9187     return;
9188
9189   info = _clutter_actor_get_layout_info (self);
9190
9191   if (priv->natural_width_set && natural_width == info->natural.width)
9192     return;
9193
9194   g_object_freeze_notify (G_OBJECT (self));
9195
9196   clutter_actor_store_old_geometry (self, &old);
9197
9198   info->natural.width = natural_width;
9199   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9200   clutter_actor_set_natural_width_set (self, TRUE);
9201
9202   clutter_actor_notify_if_geometry_changed (self, &old);
9203
9204   g_object_thaw_notify (G_OBJECT (self));
9205
9206   clutter_actor_queue_relayout (self);
9207 }
9208
9209 static void
9210 clutter_actor_set_natural_height (ClutterActor *self,
9211                                   gfloat        natural_height)
9212 {
9213   ClutterActorPrivate *priv = self->priv;
9214   ClutterActorBox old = { 0, };
9215   ClutterLayoutInfo *info;
9216
9217   /* if we are setting the size on a top-level actor and the
9218    * backend only supports static top-levels (e.g. framebuffers)
9219    * then we ignore the passed value and we override it with
9220    * the stage implementation's preferred size.
9221    */
9222   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9223       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9224     return;
9225
9226   info = _clutter_actor_get_layout_info (self);
9227
9228   if (priv->natural_height_set && natural_height == info->natural.height)
9229     return;
9230
9231   g_object_freeze_notify (G_OBJECT (self));
9232
9233   clutter_actor_store_old_geometry (self, &old);
9234
9235   info->natural.height = natural_height;
9236   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9237   clutter_actor_set_natural_height_set (self, TRUE);
9238
9239   clutter_actor_notify_if_geometry_changed (self, &old);
9240
9241   g_object_thaw_notify (G_OBJECT (self));
9242
9243   clutter_actor_queue_relayout (self);
9244 }
9245
9246 static void
9247 clutter_actor_set_min_width_set (ClutterActor *self,
9248                                  gboolean      use_min_width)
9249 {
9250   ClutterActorPrivate *priv = self->priv;
9251   ClutterActorBox old = { 0, };
9252
9253   if (priv->min_width_set == (use_min_width != FALSE))
9254     return;
9255
9256   clutter_actor_store_old_geometry (self, &old);
9257
9258   priv->min_width_set = use_min_width != FALSE;
9259   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9260
9261   clutter_actor_notify_if_geometry_changed (self, &old);
9262
9263   clutter_actor_queue_relayout (self);
9264 }
9265
9266 static void
9267 clutter_actor_set_min_height_set (ClutterActor *self,
9268                                   gboolean      use_min_height)
9269 {
9270   ClutterActorPrivate *priv = self->priv;
9271   ClutterActorBox old = { 0, };
9272
9273   if (priv->min_height_set == (use_min_height != FALSE))
9274     return;
9275
9276   clutter_actor_store_old_geometry (self, &old);
9277
9278   priv->min_height_set = use_min_height != FALSE;
9279   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9280
9281   clutter_actor_notify_if_geometry_changed (self, &old);
9282
9283   clutter_actor_queue_relayout (self);
9284 }
9285
9286 static void
9287 clutter_actor_set_natural_width_set (ClutterActor *self,
9288                                      gboolean      use_natural_width)
9289 {
9290   ClutterActorPrivate *priv = self->priv;
9291   ClutterActorBox old = { 0, };
9292
9293   if (priv->natural_width_set == (use_natural_width != FALSE))
9294     return;
9295
9296   clutter_actor_store_old_geometry (self, &old);
9297
9298   priv->natural_width_set = use_natural_width != FALSE;
9299   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9300
9301   clutter_actor_notify_if_geometry_changed (self, &old);
9302
9303   clutter_actor_queue_relayout (self);
9304 }
9305
9306 static void
9307 clutter_actor_set_natural_height_set (ClutterActor *self,
9308                                       gboolean      use_natural_height)
9309 {
9310   ClutterActorPrivate *priv = self->priv;
9311   ClutterActorBox old = { 0, };
9312
9313   if (priv->natural_height_set == (use_natural_height != FALSE))
9314     return;
9315
9316   clutter_actor_store_old_geometry (self, &old);
9317
9318   priv->natural_height_set = use_natural_height != FALSE;
9319   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9320
9321   clutter_actor_notify_if_geometry_changed (self, &old);
9322
9323   clutter_actor_queue_relayout (self);
9324 }
9325
9326 /**
9327  * clutter_actor_set_request_mode:
9328  * @self: a #ClutterActor
9329  * @mode: the request mode
9330  *
9331  * Sets the geometry request mode of @self.
9332  *
9333  * The @mode determines the order for invoking
9334  * clutter_actor_get_preferred_width() and
9335  * clutter_actor_get_preferred_height()
9336  *
9337  * Since: 1.2
9338  */
9339 void
9340 clutter_actor_set_request_mode (ClutterActor       *self,
9341                                 ClutterRequestMode  mode)
9342 {
9343   ClutterActorPrivate *priv;
9344
9345   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9346
9347   priv = self->priv;
9348
9349   if (priv->request_mode == mode)
9350     return;
9351
9352   priv->request_mode = mode;
9353
9354   priv->needs_width_request = TRUE;
9355   priv->needs_height_request = TRUE;
9356
9357   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9358
9359   clutter_actor_queue_relayout (self);
9360 }
9361
9362 /**
9363  * clutter_actor_get_request_mode:
9364  * @self: a #ClutterActor
9365  *
9366  * Retrieves the geometry request mode of @self
9367  *
9368  * Return value: the request mode for the actor
9369  *
9370  * Since: 1.2
9371  */
9372 ClutterRequestMode
9373 clutter_actor_get_request_mode (ClutterActor *self)
9374 {
9375   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9376                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9377
9378   return self->priv->request_mode;
9379 }
9380
9381 /* variant of set_width() without checks and without notification
9382  * freeze+thaw, for internal usage only
9383  */
9384 static inline void
9385 clutter_actor_set_width_internal (ClutterActor *self,
9386                                   gfloat        width)
9387 {
9388   if (width >= 0)
9389     {
9390       /* the Stage will use the :min-width to control the minimum
9391        * width to be resized to, so we should not be setting it
9392        * along with the :natural-width
9393        */
9394       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9395         clutter_actor_set_min_width (self, width);
9396
9397       clutter_actor_set_natural_width (self, width);
9398     }
9399   else
9400     {
9401       /* we only unset the :natural-width for the Stage */
9402       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9403         clutter_actor_set_min_width_set (self, FALSE);
9404
9405       clutter_actor_set_natural_width_set (self, FALSE);
9406     }
9407 }
9408
9409 /* variant of set_height() without checks and without notification
9410  * freeze+thaw, for internal usage only
9411  */
9412 static inline void
9413 clutter_actor_set_height_internal (ClutterActor *self,
9414                                    gfloat        height)
9415 {
9416   if (height >= 0)
9417     {
9418       /* see the comment above in set_width_internal() */
9419       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9420         clutter_actor_set_min_height (self, height);
9421
9422       clutter_actor_set_natural_height (self, height);
9423     }
9424   else
9425     {
9426       /* see the comment above in set_width_internal() */
9427       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9428         clutter_actor_set_min_height_set (self, FALSE);
9429
9430       clutter_actor_set_natural_height_set (self, FALSE);
9431     }
9432 }
9433
9434 static void
9435 clutter_actor_set_size_internal (ClutterActor      *self,
9436                                  const ClutterSize *size)
9437 {
9438   if (size != NULL)
9439     {
9440       clutter_actor_set_width_internal (self, size->width);
9441       clutter_actor_set_height_internal (self, size->height);
9442     }
9443   else
9444     {
9445       clutter_actor_set_width_internal (self, -1);
9446       clutter_actor_set_height_internal (self, -1);
9447     }
9448 }
9449
9450 /**
9451  * clutter_actor_set_size:
9452  * @self: A #ClutterActor
9453  * @width: New width of actor in pixels, or -1
9454  * @height: New height of actor in pixels, or -1
9455  *
9456  * Sets the actor's size request in pixels. This overrides any
9457  * "normal" size request the actor would have. For example
9458  * a text actor might normally request the size of the text;
9459  * this function would force a specific size instead.
9460  *
9461  * If @width and/or @height are -1 the actor will use its
9462  * "normal" size request instead of overriding it, i.e.
9463  * you can "unset" the size with -1.
9464  *
9465  * This function sets or unsets both the minimum and natural size.
9466  */
9467 void
9468 clutter_actor_set_size (ClutterActor *self,
9469                         gfloat        width,
9470                         gfloat        height)
9471 {
9472   ClutterSize new_size;
9473
9474   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9475
9476   clutter_size_init (&new_size, width, height);
9477
9478   if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9479     {
9480       /* minor optimization: if we don't have a duration then we can
9481        * skip the get_size() below, to avoid the chance of going through
9482        * get_preferred_width() and get_preferred_height() just to jump to
9483        * a new desired size
9484        */
9485       if (clutter_actor_get_easing_duration (self) == 0)
9486         {
9487           g_object_freeze_notify (G_OBJECT (self));
9488
9489           clutter_actor_set_size_internal (self, &new_size);
9490
9491           g_object_thaw_notify (G_OBJECT (self));
9492
9493           return;
9494         }
9495       else
9496         {
9497           ClutterSize cur_size;
9498
9499           clutter_size_init (&cur_size,
9500                              clutter_actor_get_width (self),
9501                              clutter_actor_get_height (self));
9502
9503          _clutter_actor_create_transition (self,
9504                                            obj_props[PROP_SIZE],
9505                                            &cur_size,
9506                                            &new_size);
9507         }
9508     }
9509   else
9510     _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9511
9512   clutter_actor_queue_relayout (self);
9513 }
9514
9515 /**
9516  * clutter_actor_get_size:
9517  * @self: A #ClutterActor
9518  * @width: (out) (allow-none): return location for the width, or %NULL.
9519  * @height: (out) (allow-none): return location for the height, or %NULL.
9520  *
9521  * This function tries to "do what you mean" and return
9522  * the size an actor will have. If the actor has a valid
9523  * allocation, the allocation will be returned; otherwise,
9524  * the actors natural size request will be returned.
9525  *
9526  * If you care whether you get the request vs. the allocation, you
9527  * should probably call a different function like
9528  * clutter_actor_get_allocation_box() or
9529  * clutter_actor_get_preferred_width().
9530  *
9531  * Since: 0.2
9532  */
9533 void
9534 clutter_actor_get_size (ClutterActor *self,
9535                         gfloat       *width,
9536                         gfloat       *height)
9537 {
9538   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9539
9540   if (width)
9541     *width = clutter_actor_get_width (self);
9542
9543   if (height)
9544     *height = clutter_actor_get_height (self);
9545 }
9546
9547 /**
9548  * clutter_actor_get_position:
9549  * @self: a #ClutterActor
9550  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9551  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9552  *
9553  * This function tries to "do what you mean" and tell you where the
9554  * actor is, prior to any transformations. Retrieves the fixed
9555  * position of an actor in pixels, if one has been set; otherwise, if
9556  * the allocation is valid, returns the actor's allocated position;
9557  * otherwise, returns 0,0.
9558  *
9559  * The returned position is in pixels.
9560  *
9561  * Since: 0.6
9562  */
9563 void
9564 clutter_actor_get_position (ClutterActor *self,
9565                             gfloat       *x,
9566                             gfloat       *y)
9567 {
9568   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9569
9570   if (x)
9571     *x = clutter_actor_get_x (self);
9572
9573   if (y)
9574     *y = clutter_actor_get_y (self);
9575 }
9576
9577 /**
9578  * clutter_actor_get_transformed_position:
9579  * @self: A #ClutterActor
9580  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9581  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9582  *
9583  * Gets the absolute position of an actor, in pixels relative to the stage.
9584  *
9585  * Since: 0.8
9586  */
9587 void
9588 clutter_actor_get_transformed_position (ClutterActor *self,
9589                                         gfloat       *x,
9590                                         gfloat       *y)
9591 {
9592   ClutterVertex v1;
9593   ClutterVertex v2;
9594
9595   v1.x = v1.y = v1.z = 0;
9596   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9597
9598   if (x)
9599     *x = v2.x;
9600
9601   if (y)
9602     *y = v2.y;
9603 }
9604
9605 /**
9606  * clutter_actor_get_transformed_size:
9607  * @self: A #ClutterActor
9608  * @width: (out) (allow-none): return location for the width, or %NULL
9609  * @height: (out) (allow-none): return location for the height, or %NULL
9610  *
9611  * Gets the absolute size of an actor in pixels, taking into account the
9612  * scaling factors.
9613  *
9614  * If the actor has a valid allocation, the allocated size will be used.
9615  * If the actor has not a valid allocation then the preferred size will
9616  * be transformed and returned.
9617  *
9618  * If you want the transformed allocation, see
9619  * clutter_actor_get_abs_allocation_vertices() instead.
9620  *
9621  * <note>When the actor (or one of its ancestors) is rotated around the
9622  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9623  * as a generic quadrangle; in that case this function returns the size
9624  * of the smallest rectangle that encapsulates the entire quad. Please
9625  * note that in this case no assumptions can be made about the relative
9626  * position of this envelope to the absolute position of the actor, as
9627  * returned by clutter_actor_get_transformed_position(); if you need this
9628  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9629  * to get the coords of the actual quadrangle.</note>
9630  *
9631  * Since: 0.8
9632  */
9633 void
9634 clutter_actor_get_transformed_size (ClutterActor *self,
9635                                     gfloat       *width,
9636                                     gfloat       *height)
9637 {
9638   ClutterActorPrivate *priv;
9639   ClutterVertex v[4];
9640   gfloat x_min, x_max, y_min, y_max;
9641   gint i;
9642
9643   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9644
9645   priv = self->priv;
9646
9647   /* if the actor hasn't been allocated yet, get the preferred
9648    * size and transform that
9649    */
9650   if (priv->needs_allocation)
9651     {
9652       gfloat natural_width, natural_height;
9653       ClutterActorBox box;
9654
9655       /* Make a fake allocation to transform.
9656        *
9657        * NB: _clutter_actor_transform_and_project_box expects a box in
9658        * the actor's coordinate space... */
9659
9660       box.x1 = 0;
9661       box.y1 = 0;
9662
9663       natural_width = natural_height = 0;
9664       clutter_actor_get_preferred_size (self, NULL, NULL,
9665                                         &natural_width,
9666                                         &natural_height);
9667
9668       box.x2 = natural_width;
9669       box.y2 = natural_height;
9670
9671       _clutter_actor_transform_and_project_box (self, &box, v);
9672     }
9673   else
9674     clutter_actor_get_abs_allocation_vertices (self, v);
9675
9676   x_min = x_max = v[0].x;
9677   y_min = y_max = v[0].y;
9678
9679   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9680     {
9681       if (v[i].x < x_min)
9682         x_min = v[i].x;
9683
9684       if (v[i].x > x_max)
9685         x_max = v[i].x;
9686
9687       if (v[i].y < y_min)
9688         y_min = v[i].y;
9689
9690       if (v[i].y > y_max)
9691         y_max = v[i].y;
9692     }
9693
9694   if (width)
9695     *width  = x_max - x_min;
9696
9697   if (height)
9698     *height = y_max - y_min;
9699 }
9700
9701 /**
9702  * clutter_actor_get_width:
9703  * @self: A #ClutterActor
9704  *
9705  * Retrieves the width of a #ClutterActor.
9706  *
9707  * If the actor has a valid allocation, this function will return the
9708  * width of the allocated area given to the actor.
9709  *
9710  * If the actor does not have a valid allocation, this function will
9711  * return the actor's natural width, that is the preferred width of
9712  * the actor.
9713  *
9714  * If you care whether you get the preferred width or the width that
9715  * has been assigned to the actor, you should probably call a different
9716  * function like clutter_actor_get_allocation_box() to retrieve the
9717  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9718  * preferred width.
9719  *
9720  * If an actor has a fixed width, for instance a width that has been
9721  * assigned using clutter_actor_set_width(), the width returned will
9722  * be the same value.
9723  *
9724  * Return value: the width of the actor, in pixels
9725  */
9726 gfloat
9727 clutter_actor_get_width (ClutterActor *self)
9728 {
9729   ClutterActorPrivate *priv;
9730
9731   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9732
9733   priv = self->priv;
9734
9735   if (priv->needs_allocation)
9736     {
9737       gfloat natural_width = 0;
9738
9739       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9740         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9741       else
9742         {
9743           gfloat natural_height = 0;
9744
9745           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9746           clutter_actor_get_preferred_width (self, natural_height,
9747                                              NULL,
9748                                              &natural_width);
9749         }
9750
9751       return natural_width;
9752     }
9753   else
9754     return priv->allocation.x2 - priv->allocation.x1;
9755 }
9756
9757 /**
9758  * clutter_actor_get_height:
9759  * @self: A #ClutterActor
9760  *
9761  * Retrieves the height of a #ClutterActor.
9762  *
9763  * If the actor has a valid allocation, this function will return the
9764  * height of the allocated area given to the actor.
9765  *
9766  * If the actor does not have a valid allocation, this function will
9767  * return the actor's natural height, that is the preferred height of
9768  * the actor.
9769  *
9770  * If you care whether you get the preferred height or the height that
9771  * has been assigned to the actor, you should probably call a different
9772  * function like clutter_actor_get_allocation_box() to retrieve the
9773  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9774  * preferred height.
9775  *
9776  * If an actor has a fixed height, for instance a height that has been
9777  * assigned using clutter_actor_set_height(), the height returned will
9778  * be the same value.
9779  *
9780  * Return value: the height of the actor, in pixels
9781  */
9782 gfloat
9783 clutter_actor_get_height (ClutterActor *self)
9784 {
9785   ClutterActorPrivate *priv;
9786
9787   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9788
9789   priv = self->priv;
9790
9791   if (priv->needs_allocation)
9792     {
9793       gfloat natural_height = 0;
9794
9795       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9796         {
9797           gfloat natural_width = 0;
9798
9799           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9800           clutter_actor_get_preferred_height (self, natural_width,
9801                                               NULL, &natural_height);
9802         }
9803       else
9804         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9805
9806       return natural_height;
9807     }
9808   else
9809     return priv->allocation.y2 - priv->allocation.y1;
9810 }
9811
9812 /**
9813  * clutter_actor_set_width:
9814  * @self: A #ClutterActor
9815  * @width: Requested new width for the actor, in pixels, or -1
9816  *
9817  * Forces a width on an actor, causing the actor's preferred width
9818  * and height (if any) to be ignored.
9819  *
9820  * If @width is -1 the actor will use its preferred width request
9821  * instead of overriding it, i.e. you can "unset" the width with -1.
9822  *
9823  * This function sets both the minimum and natural size of the actor.
9824  *
9825  * since: 0.2
9826  */
9827 void
9828 clutter_actor_set_width (ClutterActor *self,
9829                          gfloat        width)
9830 {
9831   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9832
9833   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9834     {
9835       float cur_size;
9836
9837       /* minor optimization: if we don't have a duration
9838        * then we can skip the get_width() below, to avoid
9839        * the chance of going through get_preferred_width()
9840        * just to jump to a new desired width.
9841        */
9842       if (clutter_actor_get_easing_duration (self) == 0)
9843         {
9844           g_object_freeze_notify (G_OBJECT (self));
9845
9846           clutter_actor_set_width_internal (self, width);
9847
9848           g_object_thaw_notify (G_OBJECT (self));
9849
9850           return;
9851         }
9852       else
9853         cur_size = clutter_actor_get_width (self);
9854
9855       _clutter_actor_create_transition (self,
9856                                         obj_props[PROP_WIDTH],
9857                                         cur_size,
9858                                         width);
9859     }
9860   else
9861     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9862 }
9863
9864 /**
9865  * clutter_actor_set_height:
9866  * @self: A #ClutterActor
9867  * @height: Requested new height for the actor, in pixels, or -1
9868  *
9869  * Forces a height on an actor, causing the actor's preferred width
9870  * and height (if any) to be ignored.
9871  *
9872  * If @height is -1 the actor will use its preferred height instead of
9873  * overriding it, i.e. you can "unset" the height with -1.
9874  *
9875  * This function sets both the minimum and natural size of the actor.
9876  *
9877  * since: 0.2
9878  */
9879 void
9880 clutter_actor_set_height (ClutterActor *self,
9881                           gfloat        height)
9882 {
9883   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9884
9885   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9886     {
9887       float cur_size;
9888
9889       /* see the comment in clutter_actor_set_width() above */
9890       if (clutter_actor_get_easing_duration (self) == 0)
9891         {
9892           g_object_freeze_notify (G_OBJECT (self));
9893
9894           clutter_actor_set_height_internal (self, height);
9895
9896           g_object_thaw_notify (G_OBJECT (self));
9897
9898           return;
9899         }
9900       else
9901         cur_size = clutter_actor_get_height (self);
9902
9903       _clutter_actor_create_transition (self,
9904                                         obj_props[PROP_HEIGHT],
9905                                         cur_size,
9906                                         height);
9907     }
9908   else
9909     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9910 }
9911
9912 static inline void
9913 clutter_actor_set_x_internal (ClutterActor *self,
9914                               float         x)
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.x == x)
9923     return;
9924
9925   clutter_actor_store_old_geometry (self, &old);
9926
9927   linfo->fixed_pos.x = x;
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 inline void
9936 clutter_actor_set_y_internal (ClutterActor *self,
9937                               float         y)
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 && linfo->fixed_pos.y == y)
9946     return;
9947
9948   clutter_actor_store_old_geometry (self, &old);
9949
9950   linfo->fixed_pos.y = y;
9951   clutter_actor_set_fixed_position_set (self, TRUE);
9952
9953   clutter_actor_notify_if_geometry_changed (self, &old);
9954
9955   clutter_actor_queue_relayout (self);
9956 }
9957
9958 static void
9959 clutter_actor_set_position_internal (ClutterActor       *self,
9960                                      const ClutterPoint *position)
9961 {
9962   ClutterActorPrivate *priv = self->priv;
9963   ClutterLayoutInfo *linfo;
9964   ClutterActorBox old = { 0, };
9965
9966   linfo = _clutter_actor_get_layout_info (self);
9967
9968   if (priv->position_set &&
9969       clutter_point_equals (position, &linfo->fixed_pos))
9970     return;
9971
9972   clutter_actor_store_old_geometry (self, &old);
9973
9974   if (position != NULL)
9975     {
9976       linfo->fixed_pos = *position;
9977       clutter_actor_set_fixed_position_set (self, TRUE);
9978     }
9979   else
9980     clutter_actor_set_fixed_position_set (self, FALSE);
9981
9982   clutter_actor_notify_if_geometry_changed (self, &old);
9983
9984   clutter_actor_queue_relayout (self);
9985 }
9986
9987 /**
9988  * clutter_actor_set_x:
9989  * @self: a #ClutterActor
9990  * @x: the actor's position on the X axis
9991  *
9992  * Sets the actor's X coordinate, relative to its parent, in pixels.
9993  *
9994  * Overrides any layout manager and forces a fixed position for
9995  * the actor.
9996  *
9997  * The #ClutterActor:x property is animatable.
9998  *
9999  * Since: 0.6
10000  */
10001 void
10002 clutter_actor_set_x (ClutterActor *self,
10003                      gfloat        x)
10004 {
10005   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10006
10007   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
10008     {
10009       float cur_position = clutter_actor_get_x (self);
10010
10011       _clutter_actor_create_transition (self, obj_props[PROP_X],
10012                                         cur_position,
10013                                         x);
10014     }
10015   else
10016     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
10017 }
10018
10019 /**
10020  * clutter_actor_set_y:
10021  * @self: a #ClutterActor
10022  * @y: the actor's position on the Y axis
10023  *
10024  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
10025  *
10026  * Overrides any layout manager and forces a fixed position for
10027  * the actor.
10028  *
10029  * The #ClutterActor:y property is animatable.
10030  *
10031  * Since: 0.6
10032  */
10033 void
10034 clutter_actor_set_y (ClutterActor *self,
10035                      gfloat        y)
10036 {
10037   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10038
10039   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
10040     {
10041       float cur_position = clutter_actor_get_y (self);
10042
10043       _clutter_actor_create_transition (self, obj_props[PROP_Y],
10044                                         cur_position,
10045                                         y);
10046     }
10047   else
10048     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
10049 }
10050
10051 /**
10052  * clutter_actor_get_x:
10053  * @self: A #ClutterActor
10054  *
10055  * Retrieves the X coordinate of a #ClutterActor.
10056  *
10057  * This function tries to "do what you mean", by returning the
10058  * correct value depending on the actor's state.
10059  *
10060  * If the actor has a valid allocation, this function will return
10061  * the X coordinate of the origin of the allocation box.
10062  *
10063  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
10064  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10065  * function will return that coordinate.
10066  *
10067  * If both the allocation and a fixed position are missing, this function
10068  * will return 0.
10069  *
10070  * Return value: the X coordinate, in pixels, ignoring any
10071  *   transformation (i.e. scaling, rotation)
10072  */
10073 gfloat
10074 clutter_actor_get_x (ClutterActor *self)
10075 {
10076   ClutterActorPrivate *priv;
10077
10078   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10079
10080   priv = self->priv;
10081
10082   if (priv->needs_allocation)
10083     {
10084       if (priv->position_set)
10085         {
10086           const ClutterLayoutInfo *info;
10087
10088           info = _clutter_actor_get_layout_info_or_defaults (self);
10089
10090           return info->fixed_pos.x;
10091         }
10092       else
10093         return 0;
10094     }
10095   else
10096     return priv->allocation.x1;
10097 }
10098
10099 /**
10100  * clutter_actor_get_y:
10101  * @self: A #ClutterActor
10102  *
10103  * Retrieves the Y coordinate of a #ClutterActor.
10104  *
10105  * This function tries to "do what you mean", by returning the
10106  * correct value depending on the actor's state.
10107  *
10108  * If the actor has a valid allocation, this function will return
10109  * the Y coordinate of the origin of the allocation box.
10110  *
10111  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
10112  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10113  * function will return that coordinate.
10114  *
10115  * If both the allocation and a fixed position are missing, this function
10116  * will return 0.
10117  *
10118  * Return value: the Y coordinate, in pixels, ignoring any
10119  *   transformation (i.e. scaling, rotation)
10120  */
10121 gfloat
10122 clutter_actor_get_y (ClutterActor *self)
10123 {
10124   ClutterActorPrivate *priv;
10125
10126   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10127
10128   priv = self->priv;
10129
10130   if (priv->needs_allocation)
10131     {
10132       if (priv->position_set)
10133         {
10134           const ClutterLayoutInfo *info;
10135
10136           info = _clutter_actor_get_layout_info_or_defaults (self);
10137
10138           return info->fixed_pos.y;
10139         }
10140       else
10141         return 0;
10142     }
10143   else
10144     return priv->allocation.y1;
10145 }
10146
10147 /**
10148  * clutter_actor_set_scale:
10149  * @self: A #ClutterActor
10150  * @scale_x: double factor to scale actor by horizontally.
10151  * @scale_y: double factor to scale actor by vertically.
10152  *
10153  * Scales an actor with the given factors. The scaling is relative to
10154  * the scale center and the anchor point. The scale center is
10155  * unchanged by this function and defaults to 0,0.
10156  *
10157  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10158  * animatable.
10159  *
10160  * Since: 0.2
10161  */
10162 void
10163 clutter_actor_set_scale (ClutterActor *self,
10164                          gdouble       scale_x,
10165                          gdouble       scale_y)
10166 {
10167   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10168
10169   g_object_freeze_notify (G_OBJECT (self));
10170
10171   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10172   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10173
10174   g_object_thaw_notify (G_OBJECT (self));
10175 }
10176
10177 /**
10178  * clutter_actor_set_scale_full:
10179  * @self: A #ClutterActor
10180  * @scale_x: double factor to scale actor by horizontally.
10181  * @scale_y: double factor to scale actor by vertically.
10182  * @center_x: X coordinate of the center of the scale.
10183  * @center_y: Y coordinate of the center of the scale
10184  *
10185  * Scales an actor with the given factors around the given center
10186  * point. The center point is specified in pixels relative to the
10187  * anchor point (usually the top left corner of the actor).
10188  *
10189  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10190  * are animatable.
10191  *
10192  * Since: 1.0
10193  */
10194 void
10195 clutter_actor_set_scale_full (ClutterActor *self,
10196                               gdouble       scale_x,
10197                               gdouble       scale_y,
10198                               gfloat        center_x,
10199                               gfloat        center_y)
10200 {
10201   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10202
10203   g_object_freeze_notify (G_OBJECT (self));
10204
10205   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10206   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10207   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10208   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10209
10210   g_object_thaw_notify (G_OBJECT (self));
10211 }
10212
10213 /**
10214  * clutter_actor_set_scale_with_gravity:
10215  * @self: A #ClutterActor
10216  * @scale_x: double factor to scale actor by horizontally.
10217  * @scale_y: double factor to scale actor by vertically.
10218  * @gravity: the location of the scale center expressed as a compass
10219  * direction.
10220  *
10221  * Scales an actor with the given factors around the given
10222  * center point. The center point is specified as one of the compass
10223  * directions in #ClutterGravity. For example, setting it to north
10224  * will cause the top of the actor to remain unchanged and the rest of
10225  * the actor to expand left, right and downwards.
10226  *
10227  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10228  * animatable.
10229  *
10230  * Since: 1.0
10231  */
10232 void
10233 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
10234                                       gdouble         scale_x,
10235                                       gdouble         scale_y,
10236                                       ClutterGravity  gravity)
10237 {
10238   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10239
10240   g_object_freeze_notify (G_OBJECT (self));
10241
10242   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10243   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10244   clutter_actor_set_scale_gravity (self, gravity);
10245
10246   g_object_thaw_notify (G_OBJECT (self));
10247 }
10248
10249 /**
10250  * clutter_actor_get_scale:
10251  * @self: A #ClutterActor
10252  * @scale_x: (out) (allow-none): Location to store horizonal
10253  *   scale factor, or %NULL.
10254  * @scale_y: (out) (allow-none): Location to store vertical
10255  *   scale factor, or %NULL.
10256  *
10257  * Retrieves an actors scale factors.
10258  *
10259  * Since: 0.2
10260  */
10261 void
10262 clutter_actor_get_scale (ClutterActor *self,
10263                          gdouble      *scale_x,
10264                          gdouble      *scale_y)
10265 {
10266   const ClutterTransformInfo *info;
10267
10268   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10269
10270   info = _clutter_actor_get_transform_info_or_defaults (self);
10271
10272   if (scale_x)
10273     *scale_x = info->scale_x;
10274
10275   if (scale_y)
10276     *scale_y = info->scale_y;
10277 }
10278
10279 /**
10280  * clutter_actor_get_scale_center:
10281  * @self: A #ClutterActor
10282  * @center_x: (out) (allow-none): Location to store the X position
10283  *   of the scale center, or %NULL.
10284  * @center_y: (out) (allow-none): Location to store the Y position
10285  *   of the scale center, or %NULL.
10286  *
10287  * Retrieves the scale center coordinate in pixels relative to the top
10288  * left corner of the actor. If the scale center was specified using a
10289  * #ClutterGravity this will calculate the pixel offset using the
10290  * current size of the actor.
10291  *
10292  * Since: 1.0
10293  */
10294 void
10295 clutter_actor_get_scale_center (ClutterActor *self,
10296                                 gfloat       *center_x,
10297                                 gfloat       *center_y)
10298 {
10299   const ClutterTransformInfo *info;
10300
10301   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10302
10303   info = _clutter_actor_get_transform_info_or_defaults (self);
10304
10305   clutter_anchor_coord_get_units (self, &info->scale_center,
10306                                   center_x,
10307                                   center_y,
10308                                   NULL);
10309 }
10310
10311 /**
10312  * clutter_actor_get_scale_gravity:
10313  * @self: A #ClutterActor
10314  *
10315  * Retrieves the scale center as a compass direction. If the scale
10316  * center was specified in pixels or units this will return
10317  * %CLUTTER_GRAVITY_NONE.
10318  *
10319  * Return value: the scale gravity
10320  *
10321  * Since: 1.0
10322  */
10323 ClutterGravity
10324 clutter_actor_get_scale_gravity (ClutterActor *self)
10325 {
10326   const ClutterTransformInfo *info;
10327
10328   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10329
10330   info = _clutter_actor_get_transform_info_or_defaults (self);
10331
10332   return clutter_anchor_coord_get_gravity (&info->scale_center);
10333 }
10334
10335 static inline void
10336 clutter_actor_set_opacity_internal (ClutterActor *self,
10337                                     guint8        opacity)
10338 {
10339   ClutterActorPrivate *priv = self->priv;
10340
10341   if (priv->opacity != opacity)
10342     {
10343       priv->opacity = opacity;
10344
10345       /* Queue a redraw from the flatten effect so that it can use
10346          its cached image if available instead of having to redraw the
10347          actual actor. If it doesn't end up using the FBO then the
10348          effect is still able to continue the paint anyway. If there
10349          is no flatten effect yet then this is equivalent to queueing
10350          a full redraw */
10351       _clutter_actor_queue_redraw_full (self,
10352                                         0, /* flags */
10353                                         NULL, /* clip */
10354                                         priv->flatten_effect);
10355
10356       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10357     }
10358 }
10359
10360 /**
10361  * clutter_actor_set_opacity:
10362  * @self: A #ClutterActor
10363  * @opacity: New opacity value for the actor.
10364  *
10365  * Sets the actor's opacity, with zero being completely transparent and
10366  * 255 (0xff) being fully opaque.
10367  *
10368  * The #ClutterActor:opacity property is animatable.
10369  */
10370 void
10371 clutter_actor_set_opacity (ClutterActor *self,
10372                            guint8        opacity)
10373 {
10374   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10375
10376   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10377     {
10378       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10379                                         self->priv->opacity,
10380                                         opacity);
10381     }
10382   else
10383     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10384 }
10385
10386 /*
10387  * clutter_actor_get_paint_opacity_internal:
10388  * @self: a #ClutterActor
10389  *
10390  * Retrieves the absolute opacity of the actor, as it appears on the stage
10391  *
10392  * This function does not do type checks
10393  *
10394  * Return value: the absolute opacity of the actor
10395  */
10396 static guint8
10397 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10398 {
10399   ClutterActorPrivate *priv = self->priv;
10400   ClutterActor *parent;
10401
10402   /* override the top-level opacity to always be 255; even in
10403    * case of ClutterStage:use-alpha being TRUE we want the rest
10404    * of the scene to be painted
10405    */
10406   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10407     return 255;
10408
10409   if (priv->opacity_override >= 0)
10410     return priv->opacity_override;
10411
10412   parent = priv->parent;
10413
10414   /* Factor in the actual actors opacity with parents */
10415   if (parent != NULL)
10416     {
10417       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10418
10419       if (opacity != 0xff)
10420         return (opacity * priv->opacity) / 0xff;
10421     }
10422
10423   return priv->opacity;
10424
10425 }
10426
10427 /**
10428  * clutter_actor_get_paint_opacity:
10429  * @self: A #ClutterActor
10430  *
10431  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10432  *
10433  * This function traverses the hierarchy chain and composites the opacity of
10434  * the actor with that of its parents.
10435  *
10436  * This function is intended for subclasses to use in the paint virtual
10437  * function, to paint themselves with the correct opacity.
10438  *
10439  * Return value: The actor opacity value.
10440  *
10441  * Since: 0.8
10442  */
10443 guint8
10444 clutter_actor_get_paint_opacity (ClutterActor *self)
10445 {
10446   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10447
10448   return clutter_actor_get_paint_opacity_internal (self);
10449 }
10450
10451 /**
10452  * clutter_actor_get_opacity:
10453  * @self: a #ClutterActor
10454  *
10455  * Retrieves the opacity value of an actor, as set by
10456  * clutter_actor_set_opacity().
10457  *
10458  * For retrieving the absolute opacity of the actor inside a paint
10459  * virtual function, see clutter_actor_get_paint_opacity().
10460  *
10461  * Return value: the opacity of the actor
10462  */
10463 guint8
10464 clutter_actor_get_opacity (ClutterActor *self)
10465 {
10466   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10467
10468   return self->priv->opacity;
10469 }
10470
10471 /**
10472  * clutter_actor_set_offscreen_redirect:
10473  * @self: A #ClutterActor
10474  * @redirect: New offscreen redirect flags for the actor.
10475  *
10476  * Defines the circumstances where the actor should be redirected into
10477  * an offscreen image. The offscreen image is used to flatten the
10478  * actor into a single image while painting for two main reasons.
10479  * Firstly, when the actor is painted a second time without any of its
10480  * contents changing it can simply repaint the cached image without
10481  * descending further down the actor hierarchy. Secondly, it will make
10482  * the opacity look correct even if there are overlapping primitives
10483  * in the actor.
10484  *
10485  * Caching the actor could in some cases be a performance win and in
10486  * some cases be a performance lose so it is important to determine
10487  * which value is right for an actor before modifying this value. For
10488  * example, there is never any reason to flatten an actor that is just
10489  * a single texture (such as a #ClutterTexture) because it is
10490  * effectively already cached in an image so the offscreen would be
10491  * redundant. Also if the actor contains primitives that are far apart
10492  * with a large transparent area in the middle (such as a large
10493  * CluterGroup with a small actor in the top left and a small actor in
10494  * the bottom right) then the cached image will contain the entire
10495  * image of the large area and the paint will waste time blending all
10496  * of the transparent pixels in the middle.
10497  *
10498  * The default method of implementing opacity on a container simply
10499  * forwards on the opacity to all of the children. If the children are
10500  * overlapping then it will appear as if they are two separate glassy
10501  * objects and there will be a break in the color where they
10502  * overlap. By redirecting to an offscreen buffer it will be as if the
10503  * two opaque objects are combined into one and then made transparent
10504  * which is usually what is expected.
10505  *
10506  * The image below demonstrates the difference between redirecting and
10507  * not. The image shows two Clutter groups, each containing a red and
10508  * a green rectangle which overlap. The opacity on the group is set to
10509  * 128 (which is 50%). When the offscreen redirect is not used, the
10510  * red rectangle can be seen through the blue rectangle as if the two
10511  * rectangles were separately transparent. When the redirect is used
10512  * the group as a whole is transparent instead so the red rectangle is
10513  * not visible where they overlap.
10514  *
10515  * <figure id="offscreen-redirect">
10516  *   <title>Sample of using an offscreen redirect for transparency</title>
10517  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10518  * </figure>
10519  *
10520  * The default value for this property is 0, so we effectively will
10521  * never redirect an actor offscreen by default. This means that there
10522  * are times that transparent actors may look glassy as described
10523  * above. The reason this is the default is because there is a
10524  * performance trade off between quality and performance here. In many
10525  * cases the default form of glassy opacity looks good enough, but if
10526  * it's not you will need to set the
10527  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10528  * redirection for opacity.
10529  *
10530  * Custom actors that don't contain any overlapping primitives are
10531  * recommended to override the has_overlaps() virtual to return %FALSE
10532  * for maximum efficiency.
10533  *
10534  * Since: 1.8
10535  */
10536 void
10537 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10538                                       ClutterOffscreenRedirect redirect)
10539 {
10540   ClutterActorPrivate *priv;
10541
10542   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10543
10544   priv = self->priv;
10545
10546   if (priv->offscreen_redirect != redirect)
10547     {
10548       priv->offscreen_redirect = redirect;
10549
10550       /* Queue a redraw from the effect so that it can use its cached
10551          image if available instead of having to redraw the actual
10552          actor. If it doesn't end up using the FBO then the effect is
10553          still able to continue the paint anyway. If there is no
10554          effect then this is equivalent to queuing a full redraw */
10555       _clutter_actor_queue_redraw_full (self,
10556                                         0, /* flags */
10557                                         NULL, /* clip */
10558                                         priv->flatten_effect);
10559
10560       g_object_notify_by_pspec (G_OBJECT (self),
10561                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10562     }
10563 }
10564
10565 /**
10566  * clutter_actor_get_offscreen_redirect:
10567  * @self: a #ClutterActor
10568  *
10569  * Retrieves whether to redirect the actor to an offscreen buffer, as
10570  * set by clutter_actor_set_offscreen_redirect().
10571  *
10572  * Return value: the value of the offscreen-redirect property of the actor
10573  *
10574  * Since: 1.8
10575  */
10576 ClutterOffscreenRedirect
10577 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10578 {
10579   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10580
10581   return self->priv->offscreen_redirect;
10582 }
10583
10584 /**
10585  * clutter_actor_set_name:
10586  * @self: A #ClutterActor
10587  * @name: Textual tag to apply to actor
10588  *
10589  * Sets the given name to @self. The name can be used to identify
10590  * a #ClutterActor.
10591  */
10592 void
10593 clutter_actor_set_name (ClutterActor *self,
10594                         const gchar  *name)
10595 {
10596   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10597
10598   g_free (self->priv->name);
10599   self->priv->name = g_strdup (name);
10600
10601   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10602 }
10603
10604 /**
10605  * clutter_actor_get_name:
10606  * @self: A #ClutterActor
10607  *
10608  * Retrieves the name of @self.
10609  *
10610  * Return value: the name of the actor, or %NULL. The returned string is
10611  *   owned by the actor and should not be modified or freed.
10612  */
10613 const gchar *
10614 clutter_actor_get_name (ClutterActor *self)
10615 {
10616   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10617
10618   return self->priv->name;
10619 }
10620
10621 /**
10622  * clutter_actor_get_gid:
10623  * @self: A #ClutterActor
10624  *
10625  * Retrieves the unique id for @self.
10626  *
10627  * Return value: Globally unique value for this object instance.
10628  *
10629  * Since: 0.6
10630  *
10631  * Deprecated: 1.8: The id is not used any longer.
10632  */
10633 guint32
10634 clutter_actor_get_gid (ClutterActor *self)
10635 {
10636   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10637
10638   return self->priv->id;
10639 }
10640
10641 static inline void
10642 clutter_actor_set_depth_internal (ClutterActor *self,
10643                                   float         depth)
10644 {
10645   ClutterTransformInfo *info;
10646
10647   info = _clutter_actor_get_transform_info (self);
10648
10649   if (info->depth != depth)
10650     {
10651       /* Sets Z value - XXX 2.0: should we invert? */
10652       info->depth = depth;
10653
10654       self->priv->transform_valid = FALSE;
10655
10656       /* FIXME - remove this crap; sadly, there are still containers
10657        * in Clutter that depend on this utter brain damage
10658        */
10659       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10660
10661       clutter_actor_queue_redraw (self);
10662
10663       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10664     }
10665 }
10666
10667 /**
10668  * clutter_actor_set_depth:
10669  * @self: a #ClutterActor
10670  * @depth: Z co-ord
10671  *
10672  * Sets the Z coordinate of @self to @depth.
10673  *
10674  * The unit used by @depth is dependant on the perspective setup. See
10675  * also clutter_stage_set_perspective().
10676  */
10677 void
10678 clutter_actor_set_depth (ClutterActor *self,
10679                          gfloat        depth)
10680 {
10681   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10682
10683   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10684     {
10685       const ClutterTransformInfo *info;
10686
10687       info = _clutter_actor_get_transform_info_or_defaults (self);
10688
10689       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10690                                         info->depth,
10691                                         depth);
10692     }
10693   else
10694     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10695
10696   clutter_actor_queue_redraw (self);
10697 }
10698
10699 /**
10700  * clutter_actor_get_depth:
10701  * @self: a #ClutterActor
10702  *
10703  * Retrieves the depth of @self.
10704  *
10705  * Return value: the depth of the actor
10706  */
10707 gfloat
10708 clutter_actor_get_depth (ClutterActor *self)
10709 {
10710   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10711
10712   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10713 }
10714
10715 /**
10716  * clutter_actor_set_rotation:
10717  * @self: a #ClutterActor
10718  * @axis: the axis of rotation
10719  * @angle: the angle of rotation
10720  * @x: X coordinate of the rotation center
10721  * @y: Y coordinate of the rotation center
10722  * @z: Z coordinate of the rotation center
10723  *
10724  * Sets the rotation angle of @self around the given axis.
10725  *
10726  * The rotation center coordinates used depend on the value of @axis:
10727  * <itemizedlist>
10728  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10729  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10730  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10731  * </itemizedlist>
10732  *
10733  * The rotation coordinates are relative to the anchor point of the
10734  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10735  * point is set, the upper left corner is assumed as the origin.
10736  *
10737  * Since: 0.8
10738  */
10739 void
10740 clutter_actor_set_rotation (ClutterActor      *self,
10741                             ClutterRotateAxis  axis,
10742                             gdouble            angle,
10743                             gfloat             x,
10744                             gfloat             y,
10745                             gfloat             z)
10746 {
10747   ClutterVertex v;
10748
10749   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10750
10751   v.x = x;
10752   v.y = y;
10753   v.z = z;
10754
10755   g_object_freeze_notify (G_OBJECT (self));
10756
10757   clutter_actor_set_rotation_angle (self, axis, angle);
10758   clutter_actor_set_rotation_center_internal (self, axis, &v);
10759
10760   g_object_thaw_notify (G_OBJECT (self));
10761 }
10762
10763 /**
10764  * clutter_actor_set_z_rotation_from_gravity:
10765  * @self: a #ClutterActor
10766  * @angle: the angle of rotation
10767  * @gravity: the center point of the rotation
10768  *
10769  * Sets the rotation angle of @self around the Z axis using the center
10770  * point specified as a compass point. For example to rotate such that
10771  * the center of the actor remains static you can use
10772  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10773  * will move accordingly.
10774  *
10775  * Since: 1.0
10776  */
10777 void
10778 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10779                                            gdouble         angle,
10780                                            ClutterGravity  gravity)
10781 {
10782   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10783
10784   if (gravity == CLUTTER_GRAVITY_NONE)
10785     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10786   else
10787     {
10788       GObject *obj = G_OBJECT (self);
10789       ClutterTransformInfo *info;
10790
10791       info = _clutter_actor_get_transform_info (self);
10792
10793       g_object_freeze_notify (obj);
10794
10795       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10796
10797       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10798       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10799       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10800
10801       g_object_thaw_notify (obj);
10802     }
10803 }
10804
10805 /**
10806  * clutter_actor_get_rotation:
10807  * @self: a #ClutterActor
10808  * @axis: the axis of rotation
10809  * @x: (out): return value for the X coordinate of the center of rotation
10810  * @y: (out): return value for the Y coordinate of the center of rotation
10811  * @z: (out): return value for the Z coordinate of the center of rotation
10812  *
10813  * Retrieves the angle and center of rotation on the given axis,
10814  * set using clutter_actor_set_rotation().
10815  *
10816  * Return value: the angle of rotation
10817  *
10818  * Since: 0.8
10819  */
10820 gdouble
10821 clutter_actor_get_rotation (ClutterActor      *self,
10822                             ClutterRotateAxis  axis,
10823                             gfloat            *x,
10824                             gfloat            *y,
10825                             gfloat            *z)
10826 {
10827   const ClutterTransformInfo *info;
10828   const AnchorCoord *anchor_coord;
10829   gdouble retval = 0;
10830
10831   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10832
10833   info = _clutter_actor_get_transform_info_or_defaults (self);
10834
10835   switch (axis)
10836     {
10837     case CLUTTER_X_AXIS:
10838       anchor_coord = &info->rx_center;
10839       retval = info->rx_angle;
10840       break;
10841
10842     case CLUTTER_Y_AXIS:
10843       anchor_coord = &info->ry_center;
10844       retval = info->ry_angle;
10845       break;
10846
10847     case CLUTTER_Z_AXIS:
10848       anchor_coord = &info->rz_center;
10849       retval = info->rz_angle;
10850       break;
10851
10852     default:
10853       anchor_coord = NULL;
10854       retval = 0.0;
10855       break;
10856     }
10857
10858   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10859
10860   return retval;
10861 }
10862
10863 /**
10864  * clutter_actor_get_z_rotation_gravity:
10865  * @self: A #ClutterActor
10866  *
10867  * Retrieves the center for the rotation around the Z axis as a
10868  * compass direction. If the center was specified in pixels or units
10869  * this will return %CLUTTER_GRAVITY_NONE.
10870  *
10871  * Return value: the Z rotation center
10872  *
10873  * Since: 1.0
10874  */
10875 ClutterGravity
10876 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10877 {
10878   const ClutterTransformInfo *info;
10879
10880   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10881
10882   info = _clutter_actor_get_transform_info_or_defaults (self);
10883
10884   return clutter_anchor_coord_get_gravity (&info->rz_center);
10885 }
10886
10887 /**
10888  * clutter_actor_set_clip:
10889  * @self: A #ClutterActor
10890  * @xoff: X offset of the clip rectangle
10891  * @yoff: Y offset of the clip rectangle
10892  * @width: Width of the clip rectangle
10893  * @height: Height of the clip rectangle
10894  *
10895  * Sets clip area for @self. The clip area is always computed from the
10896  * upper left corner of the actor, even if the anchor point is set
10897  * otherwise.
10898  *
10899  * Since: 0.6
10900  */
10901 void
10902 clutter_actor_set_clip (ClutterActor *self,
10903                         gfloat        xoff,
10904                         gfloat        yoff,
10905                         gfloat        width,
10906                         gfloat        height)
10907 {
10908   ClutterActorPrivate *priv;
10909
10910   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10911
10912   priv = self->priv;
10913
10914   if (priv->has_clip &&
10915       priv->clip.x == xoff &&
10916       priv->clip.y == yoff &&
10917       priv->clip.width == width &&
10918       priv->clip.height == height)
10919     return;
10920
10921   priv->clip.x = xoff;
10922   priv->clip.y = yoff;
10923   priv->clip.width = width;
10924   priv->clip.height = height;
10925
10926   priv->has_clip = TRUE;
10927
10928   clutter_actor_queue_redraw (self);
10929
10930   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10931   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10932 }
10933
10934 /**
10935  * clutter_actor_remove_clip:
10936  * @self: A #ClutterActor
10937  *
10938  * Removes clip area from @self.
10939  */
10940 void
10941 clutter_actor_remove_clip (ClutterActor *self)
10942 {
10943   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10944
10945   if (!self->priv->has_clip)
10946     return;
10947
10948   self->priv->has_clip = FALSE;
10949
10950   clutter_actor_queue_redraw (self);
10951
10952   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10953 }
10954
10955 /**
10956  * clutter_actor_has_clip:
10957  * @self: a #ClutterActor
10958  *
10959  * Determines whether the actor has a clip area set or not.
10960  *
10961  * Return value: %TRUE if the actor has a clip area set.
10962  *
10963  * Since: 0.1.1
10964  */
10965 gboolean
10966 clutter_actor_has_clip (ClutterActor *self)
10967 {
10968   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10969
10970   return self->priv->has_clip;
10971 }
10972
10973 /**
10974  * clutter_actor_get_clip:
10975  * @self: a #ClutterActor
10976  * @xoff: (out) (allow-none): return location for the X offset of
10977  *   the clip rectangle, or %NULL
10978  * @yoff: (out) (allow-none): return location for the Y offset of
10979  *   the clip rectangle, or %NULL
10980  * @width: (out) (allow-none): return location for the width of
10981  *   the clip rectangle, or %NULL
10982  * @height: (out) (allow-none): return location for the height of
10983  *   the clip rectangle, or %NULL
10984  *
10985  * Gets the clip area for @self, if any is set
10986  *
10987  * Since: 0.6
10988  */
10989 void
10990 clutter_actor_get_clip (ClutterActor *self,
10991                         gfloat       *xoff,
10992                         gfloat       *yoff,
10993                         gfloat       *width,
10994                         gfloat       *height)
10995 {
10996   ClutterActorPrivate *priv;
10997
10998   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10999
11000   priv = self->priv;
11001
11002   if (!priv->has_clip)
11003     return;
11004
11005   if (xoff != NULL)
11006     *xoff = priv->clip.x;
11007
11008   if (yoff != NULL)
11009     *yoff = priv->clip.y;
11010
11011   if (width != NULL)
11012     *width = priv->clip.width;
11013
11014   if (height != NULL)
11015     *height = priv->clip.height;
11016 }
11017
11018 /**
11019  * clutter_actor_get_children:
11020  * @self: a #ClutterActor
11021  *
11022  * Retrieves the list of children of @self.
11023  *
11024  * Return value: (transfer container) (element-type ClutterActor): A newly
11025  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
11026  *   done.
11027  *
11028  * Since: 1.10
11029  */
11030 GList *
11031 clutter_actor_get_children (ClutterActor *self)
11032 {
11033   ClutterActor *iter;
11034   GList *res;
11035
11036   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11037
11038   /* we walk the list backward so that we can use prepend(),
11039    * which is O(1)
11040    */
11041   for (iter = self->priv->last_child, res = NULL;
11042        iter != NULL;
11043        iter = iter->priv->prev_sibling)
11044     {
11045       res = g_list_prepend (res, iter);
11046     }
11047
11048   return res;
11049 }
11050
11051 /*< private >
11052  * insert_child_at_depth:
11053  * @self: a #ClutterActor
11054  * @child: a #ClutterActor
11055  *
11056  * Inserts @child inside the list of children held by @self, using
11057  * the depth as the insertion criteria.
11058  *
11059  * This sadly makes the insertion not O(1), but we can keep the
11060  * list sorted so that the painters algorithm we use for painting
11061  * the children will work correctly.
11062  */
11063 static void
11064 insert_child_at_depth (ClutterActor *self,
11065                        ClutterActor *child,
11066                        gpointer      dummy G_GNUC_UNUSED)
11067 {
11068   ClutterActor *iter;
11069   float child_depth;
11070
11071   child->priv->parent = self;
11072
11073   child_depth =
11074     _clutter_actor_get_transform_info_or_defaults (child)->depth;
11075
11076   /* special-case the first child */
11077   if (self->priv->n_children == 0)
11078     {
11079       self->priv->first_child = child;
11080       self->priv->last_child = child;
11081
11082       child->priv->next_sibling = NULL;
11083       child->priv->prev_sibling = NULL;
11084
11085       return;
11086     }
11087
11088   /* Find the right place to insert the child so that it will still be
11089      sorted and the child will be after all of the actors at the same
11090      dept */
11091   for (iter = self->priv->first_child;
11092        iter != NULL;
11093        iter = iter->priv->next_sibling)
11094     {
11095       float iter_depth;
11096
11097       iter_depth =
11098         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
11099
11100       if (iter_depth > child_depth)
11101         break;
11102     }
11103
11104   if (iter != NULL)
11105     {
11106       ClutterActor *tmp = iter->priv->prev_sibling;
11107
11108       if (tmp != NULL)
11109         tmp->priv->next_sibling = child;
11110
11111       /* Insert the node before the found one */
11112       child->priv->prev_sibling = iter->priv->prev_sibling;
11113       child->priv->next_sibling = iter;
11114       iter->priv->prev_sibling = child;
11115     }
11116   else
11117     {
11118       ClutterActor *tmp = self->priv->last_child;
11119
11120       if (tmp != NULL)
11121         tmp->priv->next_sibling = child;
11122
11123       /* insert the node at the end of the list */
11124       child->priv->prev_sibling = self->priv->last_child;
11125       child->priv->next_sibling = NULL;
11126     }
11127
11128   if (child->priv->prev_sibling == NULL)
11129     self->priv->first_child = child;
11130
11131   if (child->priv->next_sibling == NULL)
11132     self->priv->last_child = child;
11133 }
11134
11135 static void
11136 insert_child_at_index (ClutterActor *self,
11137                        ClutterActor *child,
11138                        gpointer      data_)
11139 {
11140   gint index_ = GPOINTER_TO_INT (data_);
11141
11142   child->priv->parent = self;
11143
11144   if (index_ == 0)
11145     {
11146       ClutterActor *tmp = self->priv->first_child;
11147
11148       if (tmp != NULL)
11149         tmp->priv->prev_sibling = child;
11150
11151       child->priv->prev_sibling = NULL;
11152       child->priv->next_sibling = tmp;
11153     }
11154   else if (index_ < 0 || index_ >= self->priv->n_children)
11155     {
11156       ClutterActor *tmp = self->priv->last_child;
11157
11158       if (tmp != NULL)
11159         tmp->priv->next_sibling = child;
11160
11161       child->priv->prev_sibling = tmp;
11162       child->priv->next_sibling = NULL;
11163     }
11164   else
11165     {
11166       ClutterActor *iter;
11167       int i;
11168
11169       for (iter = self->priv->first_child, i = 0;
11170            iter != NULL;
11171            iter = iter->priv->next_sibling, i += 1)
11172         {
11173           if (index_ == i)
11174             {
11175               ClutterActor *tmp = iter->priv->prev_sibling;
11176
11177               child->priv->prev_sibling = tmp;
11178               child->priv->next_sibling = iter;
11179
11180               iter->priv->prev_sibling = child;
11181
11182               if (tmp != NULL)
11183                 tmp->priv->next_sibling = child;
11184
11185               break;
11186             }
11187         }
11188     }
11189
11190   if (child->priv->prev_sibling == NULL)
11191     self->priv->first_child = child;
11192
11193   if (child->priv->next_sibling == NULL)
11194     self->priv->last_child = child;
11195 }
11196
11197 static void
11198 insert_child_above (ClutterActor *self,
11199                     ClutterActor *child,
11200                     gpointer      data)
11201 {
11202   ClutterActor *sibling = data;
11203
11204   child->priv->parent = self;
11205
11206   if (sibling == NULL)
11207     sibling = self->priv->last_child;
11208
11209   child->priv->prev_sibling = sibling;
11210
11211   if (sibling != NULL)
11212     {
11213       ClutterActor *tmp = sibling->priv->next_sibling;
11214
11215       child->priv->next_sibling = tmp;
11216
11217       if (tmp != NULL)
11218         tmp->priv->prev_sibling = child;
11219
11220       sibling->priv->next_sibling = child;
11221     }
11222   else
11223     child->priv->next_sibling = NULL;
11224
11225   if (child->priv->prev_sibling == NULL)
11226     self->priv->first_child = child;
11227
11228   if (child->priv->next_sibling == NULL)
11229     self->priv->last_child = child;
11230 }
11231
11232 static void
11233 insert_child_below (ClutterActor *self,
11234                     ClutterActor *child,
11235                     gpointer      data)
11236 {
11237   ClutterActor *sibling = data;
11238
11239   child->priv->parent = self;
11240
11241   if (sibling == NULL)
11242     sibling = self->priv->first_child;
11243
11244   child->priv->next_sibling = sibling;
11245
11246   if (sibling != NULL)
11247     {
11248       ClutterActor *tmp = sibling->priv->prev_sibling;
11249
11250       child->priv->prev_sibling = tmp;
11251
11252       if (tmp != NULL)
11253         tmp->priv->next_sibling = child;
11254
11255       sibling->priv->prev_sibling = child;
11256     }
11257   else
11258     child->priv->prev_sibling = NULL;
11259
11260   if (child->priv->prev_sibling == NULL)
11261     self->priv->first_child = child;
11262
11263   if (child->priv->next_sibling == NULL)
11264     self->priv->last_child = child;
11265 }
11266
11267 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11268                                            ClutterActor *child,
11269                                            gpointer      data);
11270
11271 typedef enum {
11272   ADD_CHILD_CREATE_META        = 1 << 0,
11273   ADD_CHILD_EMIT_PARENT_SET    = 1 << 1,
11274   ADD_CHILD_EMIT_ACTOR_ADDED   = 1 << 2,
11275   ADD_CHILD_CHECK_STATE        = 1 << 3,
11276   ADD_CHILD_NOTIFY_FIRST_LAST  = 1 << 4,
11277   ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11278
11279   /* default flags for public API */
11280   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
11281                                ADD_CHILD_EMIT_PARENT_SET |
11282                                ADD_CHILD_EMIT_ACTOR_ADDED |
11283                                ADD_CHILD_CHECK_STATE |
11284                                ADD_CHILD_NOTIFY_FIRST_LAST |
11285                                ADD_CHILD_SHOW_ON_SET_PARENT,
11286
11287   /* flags for legacy/deprecated API */
11288   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
11289                                ADD_CHILD_CHECK_STATE |
11290                                ADD_CHILD_NOTIFY_FIRST_LAST |
11291                                ADD_CHILD_SHOW_ON_SET_PARENT
11292 } ClutterActorAddChildFlags;
11293
11294 /*< private >
11295  * clutter_actor_add_child_internal:
11296  * @self: a #ClutterActor
11297  * @child: a #ClutterActor
11298  * @flags: control flags for actions
11299  * @add_func: delegate function
11300  * @data: (closure): data to pass to @add_func
11301  *
11302  * Adds @child to the list of children of @self.
11303  *
11304  * The actual insertion inside the list is delegated to @add_func: this
11305  * function will just set up the state, perform basic checks, and emit
11306  * signals.
11307  *
11308  * The @flags argument is used to perform additional operations.
11309  */
11310 static inline void
11311 clutter_actor_add_child_internal (ClutterActor              *self,
11312                                   ClutterActor              *child,
11313                                   ClutterActorAddChildFlags  flags,
11314                                   ClutterActorAddChildFunc   add_func,
11315                                   gpointer                   data)
11316 {
11317   ClutterTextDirection text_dir;
11318   gboolean create_meta;
11319   gboolean emit_parent_set, emit_actor_added;
11320   gboolean check_state;
11321   gboolean notify_first_last;
11322   gboolean show_on_set_parent;
11323   ClutterActor *old_first_child, *old_last_child;
11324
11325   if (child->priv->parent != NULL)
11326     {
11327       g_warning ("The actor '%s' already has a parent, '%s'. You must "
11328                  "use clutter_actor_remove_child() first.",
11329                  _clutter_actor_get_debug_name (child),
11330                  _clutter_actor_get_debug_name (child->priv->parent));
11331       return;
11332     }
11333
11334   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11335     {
11336       g_warning ("The actor '%s' is a top-level actor, and cannot be "
11337                  "a child of another actor.",
11338                  _clutter_actor_get_debug_name (child));
11339       return;
11340     }
11341
11342 #if 0
11343   /* XXX - this check disallows calling methods that change the stacking
11344    * order within the destruction sequence, by triggering a critical
11345    * warning first, and leaving the actor in an undefined state, which
11346    * then ends up being caught by an assertion.
11347    *
11348    * the reproducible sequence is:
11349    *
11350    *   - actor gets destroyed;
11351    *   - another actor, linked to the first, will try to change the
11352    *     stacking order of the first actor;
11353    *   - changing the stacking order is a composite operation composed
11354    *     by the following steps:
11355    *     1. ref() the child;
11356    *     2. remove_child_internal(), which removes the reference;
11357    *     3. add_child_internal(), which adds a reference;
11358    *   - the state of the actor is not changed between (2) and (3), as
11359    *     it could be an expensive recomputation;
11360    *   - if (3) bails out, then the actor is in an undefined state, but
11361    *     still alive;
11362    *   - the destruction sequence terminates, but the actor is unparented
11363    *     while its state indicates being parented instead.
11364    *   - assertion failure.
11365    *
11366    * the obvious fix would be to decompose each set_child_*_sibling()
11367    * method into proper remove_child()/add_child(), with state validation;
11368    * this may cause excessive work, though, and trigger a cascade of other
11369    * bugs in code that assumes that a change in the stacking order is an
11370    * atomic operation.
11371    *
11372    * another potential fix is to just remove this check here, and let
11373    * code doing stacking order changes inside the destruction sequence
11374    * of an actor continue doing the work.
11375    *
11376    * the third fix is to silently bail out early from every
11377    * set_child_*_sibling() and set_child_at_index() method, and avoid
11378    * doing work.
11379    *
11380    * I have a preference for the second solution, since it involves the
11381    * least amount of work, and the least amount of code duplication.
11382    *
11383    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11384    */
11385   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11386     {
11387       g_warning ("The actor '%s' is currently being destroyed, and "
11388                  "cannot be added as a child of another actor.",
11389                  _clutter_actor_get_debug_name (child));
11390       return;
11391     }
11392 #endif
11393
11394   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11395   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11396   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11397   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11398   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11399   show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11400
11401   old_first_child = self->priv->first_child;
11402   old_last_child = self->priv->last_child;
11403
11404   g_object_freeze_notify (G_OBJECT (self));
11405
11406   if (create_meta)
11407     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11408
11409   g_object_ref_sink (child);
11410   child->priv->parent = NULL;
11411   child->priv->next_sibling = NULL;
11412   child->priv->prev_sibling = NULL;
11413
11414   /* delegate the actual insertion */
11415   add_func (self, child, data);
11416
11417   g_assert (child->priv->parent == self);
11418
11419   self->priv->n_children += 1;
11420
11421   self->priv->age += 1;
11422
11423   /* if push_internal() has been called then we automatically set
11424    * the flag on the actor
11425    */
11426   if (self->priv->internal_child)
11427     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11428
11429   /* children may cause their parent to expand, if they are set
11430    * to expand; if a child is not expanded then it cannot change
11431    * its parent's state. any further change later on will queue
11432    * an expand state check.
11433    *
11434    * this check, with the initial state of the needs_compute_expand
11435    * flag set to FALSE, should avoid recomputing the expand flags
11436    * state while building the actor tree.
11437    */
11438   if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
11439       (child->priv->needs_compute_expand ||
11440        child->priv->needs_x_expand ||
11441        child->priv->needs_y_expand))
11442     {
11443       clutter_actor_queue_compute_expand (self);
11444     }
11445
11446   /* clutter_actor_reparent() will emit ::parent-set for us */
11447   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11448     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11449
11450   if (check_state)
11451     {
11452       /* If parent is mapped or realized, we need to also be mapped or
11453        * realized once we're inside the parent.
11454        */
11455       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11456
11457       /* propagate the parent's text direction to the child */
11458       text_dir = clutter_actor_get_text_direction (self);
11459       clutter_actor_set_text_direction (child, text_dir);
11460     }
11461
11462   if (show_on_set_parent && child->priv->show_on_set_parent)
11463     clutter_actor_show (child);
11464
11465   if (CLUTTER_ACTOR_IS_MAPPED (child))
11466     clutter_actor_queue_redraw (child);
11467
11468   /* maintain the invariant that if an actor needs layout,
11469    * its parents do as well
11470    */
11471   if (child->priv->needs_width_request ||
11472       child->priv->needs_height_request ||
11473       child->priv->needs_allocation)
11474     {
11475       /* we work around the short-circuiting we do
11476        * in clutter_actor_queue_relayout() since we
11477        * want to force a relayout
11478        */
11479       child->priv->needs_width_request = TRUE;
11480       child->priv->needs_height_request = TRUE;
11481       child->priv->needs_allocation = TRUE;
11482
11483       clutter_actor_queue_relayout (child->priv->parent);
11484     }
11485
11486   if (emit_actor_added)
11487     g_signal_emit_by_name (self, "actor-added", child);
11488
11489   if (notify_first_last)
11490     {
11491       if (old_first_child != self->priv->first_child)
11492         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11493
11494       if (old_last_child != self->priv->last_child)
11495         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11496     }
11497
11498   g_object_thaw_notify (G_OBJECT (self));
11499 }
11500
11501 /**
11502  * clutter_actor_add_child:
11503  * @self: a #ClutterActor
11504  * @child: a #ClutterActor
11505  *
11506  * Adds @child to the children of @self.
11507  *
11508  * This function will acquire a reference on @child that will only
11509  * be released when calling clutter_actor_remove_child().
11510  *
11511  * This function will take into consideration the #ClutterActor:depth
11512  * of @child, and will keep the list of children sorted.
11513  *
11514  * This function will emit the #ClutterContainer::actor-added signal
11515  * on @self.
11516  *
11517  * Since: 1.10
11518  */
11519 void
11520 clutter_actor_add_child (ClutterActor *self,
11521                          ClutterActor *child)
11522 {
11523   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11524   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11525   g_return_if_fail (self != child);
11526   g_return_if_fail (child->priv->parent == NULL);
11527
11528   clutter_actor_add_child_internal (self, child,
11529                                     ADD_CHILD_DEFAULT_FLAGS,
11530                                     insert_child_at_depth,
11531                                     NULL);
11532 }
11533
11534 /**
11535  * clutter_actor_insert_child_at_index:
11536  * @self: a #ClutterActor
11537  * @child: a #ClutterActor
11538  * @index_: the index
11539  *
11540  * Inserts @child into the list of children of @self, using the
11541  * given @index_. If @index_ is greater than the number of children
11542  * in @self, or is less than 0, then the new child is added at the end.
11543  *
11544  * This function will acquire a reference on @child that will only
11545  * be released when calling clutter_actor_remove_child().
11546  *
11547  * This function will not take into consideration the #ClutterActor:depth
11548  * of @child.
11549  *
11550  * This function will emit the #ClutterContainer::actor-added signal
11551  * on @self.
11552  *
11553  * Since: 1.10
11554  */
11555 void
11556 clutter_actor_insert_child_at_index (ClutterActor *self,
11557                                      ClutterActor *child,
11558                                      gint          index_)
11559 {
11560   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11561   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11562   g_return_if_fail (self != child);
11563   g_return_if_fail (child->priv->parent == NULL);
11564
11565   clutter_actor_add_child_internal (self, child,
11566                                     ADD_CHILD_DEFAULT_FLAGS,
11567                                     insert_child_at_index,
11568                                     GINT_TO_POINTER (index_));
11569 }
11570
11571 /**
11572  * clutter_actor_insert_child_above:
11573  * @self: a #ClutterActor
11574  * @child: a #ClutterActor
11575  * @sibling: (allow-none): a child of @self, or %NULL
11576  *
11577  * Inserts @child into the list of children of @self, above another
11578  * child of @self or, if @sibling is %NULL, above all the children
11579  * of @self.
11580  *
11581  * This function will acquire a reference on @child that will only
11582  * be released when calling clutter_actor_remove_child().
11583  *
11584  * This function will not take into consideration the #ClutterActor:depth
11585  * of @child.
11586  *
11587  * This function will emit the #ClutterContainer::actor-added signal
11588  * on @self.
11589  *
11590  * Since: 1.10
11591  */
11592 void
11593 clutter_actor_insert_child_above (ClutterActor *self,
11594                                   ClutterActor *child,
11595                                   ClutterActor *sibling)
11596 {
11597   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11598   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11599   g_return_if_fail (self != child);
11600   g_return_if_fail (child != sibling);
11601   g_return_if_fail (child->priv->parent == NULL);
11602   g_return_if_fail (sibling == NULL ||
11603                     (CLUTTER_IS_ACTOR (sibling) &&
11604                      sibling->priv->parent == self));
11605
11606   clutter_actor_add_child_internal (self, child,
11607                                     ADD_CHILD_DEFAULT_FLAGS,
11608                                     insert_child_above,
11609                                     sibling);
11610 }
11611
11612 /**
11613  * clutter_actor_insert_child_below:
11614  * @self: a #ClutterActor
11615  * @child: a #ClutterActor
11616  * @sibling: (allow-none): a child of @self, or %NULL
11617  *
11618  * Inserts @child into the list of children of @self, below another
11619  * child of @self or, if @sibling is %NULL, below all the children
11620  * of @self.
11621  *
11622  * This function will acquire a reference on @child that will only
11623  * be released when calling clutter_actor_remove_child().
11624  *
11625  * This function will not take into consideration the #ClutterActor:depth
11626  * of @child.
11627  *
11628  * This function will emit the #ClutterContainer::actor-added signal
11629  * on @self.
11630  *
11631  * Since: 1.10
11632  */
11633 void
11634 clutter_actor_insert_child_below (ClutterActor *self,
11635                                   ClutterActor *child,
11636                                   ClutterActor *sibling)
11637 {
11638   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11639   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11640   g_return_if_fail (self != child);
11641   g_return_if_fail (child != sibling);
11642   g_return_if_fail (child->priv->parent == NULL);
11643   g_return_if_fail (sibling == NULL ||
11644                     (CLUTTER_IS_ACTOR (sibling) &&
11645                      sibling->priv->parent == self));
11646
11647   clutter_actor_add_child_internal (self, child,
11648                                     ADD_CHILD_DEFAULT_FLAGS,
11649                                     insert_child_below,
11650                                     sibling);
11651 }
11652
11653 /**
11654  * clutter_actor_set_parent:
11655  * @self: A #ClutterActor
11656  * @parent: A new #ClutterActor parent
11657  *
11658  * Sets the parent of @self to @parent.
11659  *
11660  * This function will result in @parent acquiring a reference on @self,
11661  * eventually by sinking its floating reference first. The reference
11662  * will be released by clutter_actor_unparent().
11663  *
11664  * This function should only be called by legacy #ClutterActor<!-- -->s
11665  * implementing the #ClutterContainer interface.
11666  *
11667  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11668  */
11669 void
11670 clutter_actor_set_parent (ClutterActor *self,
11671                           ClutterActor *parent)
11672 {
11673   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11674   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11675   g_return_if_fail (self != parent);
11676   g_return_if_fail (self->priv->parent == NULL);
11677
11678   /* as this function will be called inside ClutterContainer::add
11679    * implementations or when building up a composite actor, we have
11680    * to preserve the old behaviour, and not create child meta or
11681    * emit the ::actor-added signal, to avoid recursion or double
11682    * emissions
11683    */
11684   clutter_actor_add_child_internal (parent, self,
11685                                     ADD_CHILD_LEGACY_FLAGS,
11686                                     insert_child_at_depth,
11687                                     NULL);
11688 }
11689
11690 /**
11691  * clutter_actor_get_parent:
11692  * @self: A #ClutterActor
11693  *
11694  * Retrieves the parent of @self.
11695  *
11696  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11697  *  if no parent is set
11698  */
11699 ClutterActor *
11700 clutter_actor_get_parent (ClutterActor *self)
11701 {
11702   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11703
11704   return self->priv->parent;
11705 }
11706
11707 /**
11708  * clutter_actor_get_paint_visibility:
11709  * @self: A #ClutterActor
11710  *
11711  * Retrieves the 'paint' visibility of an actor recursively checking for non
11712  * visible parents.
11713  *
11714  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11715  *
11716  * Return Value: %TRUE if the actor is visibile and will be painted.
11717  *
11718  * Since: 0.8.4
11719  */
11720 gboolean
11721 clutter_actor_get_paint_visibility (ClutterActor *actor)
11722 {
11723   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11724
11725   return CLUTTER_ACTOR_IS_MAPPED (actor);
11726 }
11727
11728 /**
11729  * clutter_actor_remove_child:
11730  * @self: a #ClutterActor
11731  * @child: a #ClutterActor
11732  *
11733  * Removes @child from the children of @self.
11734  *
11735  * This function will release the reference added by
11736  * clutter_actor_add_child(), so if you want to keep using @child
11737  * you will have to acquire a referenced on it before calling this
11738  * function.
11739  *
11740  * This function will emit the #ClutterContainer::actor-removed
11741  * signal on @self.
11742  *
11743  * Since: 1.10
11744  */
11745 void
11746 clutter_actor_remove_child (ClutterActor *self,
11747                             ClutterActor *child)
11748 {
11749   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11750   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11751   g_return_if_fail (self != child);
11752   g_return_if_fail (child->priv->parent != NULL);
11753   g_return_if_fail (child->priv->parent == self);
11754
11755   clutter_actor_remove_child_internal (self, child,
11756                                        REMOVE_CHILD_DEFAULT_FLAGS);
11757 }
11758
11759 /**
11760  * clutter_actor_remove_all_children:
11761  * @self: a #ClutterActor
11762  *
11763  * Removes all children of @self.
11764  *
11765  * This function releases the reference added by inserting a child actor
11766  * in the list of children of @self.
11767  *
11768  * If the reference count of a child drops to zero, the child will be
11769  * destroyed. If you want to ensure the destruction of all the children
11770  * of @self, use clutter_actor_destroy_all_children().
11771  *
11772  * Since: 1.10
11773  */
11774 void
11775 clutter_actor_remove_all_children (ClutterActor *self)
11776 {
11777   ClutterActorIter iter;
11778
11779   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11780
11781   if (self->priv->n_children == 0)
11782     return;
11783
11784   g_object_freeze_notify (G_OBJECT (self));
11785
11786   clutter_actor_iter_init (&iter, self);
11787   while (clutter_actor_iter_next (&iter, NULL))
11788     clutter_actor_iter_remove (&iter);
11789
11790   g_object_thaw_notify (G_OBJECT (self));
11791
11792   /* sanity check */
11793   g_assert (self->priv->first_child == NULL);
11794   g_assert (self->priv->last_child == NULL);
11795   g_assert (self->priv->n_children == 0);
11796 }
11797
11798 /**
11799  * clutter_actor_destroy_all_children:
11800  * @self: a #ClutterActor
11801  *
11802  * Destroys all children of @self.
11803  *
11804  * This function releases the reference added by inserting a child
11805  * actor in the list of children of @self, and ensures that the
11806  * #ClutterActor::destroy signal is emitted on each child of the
11807  * actor.
11808  *
11809  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11810  * when its reference count drops to 0; the default handler of the
11811  * #ClutterActor::destroy signal will destroy all the children of an
11812  * actor. This function ensures that all children are destroyed, instead
11813  * of just removed from @self, unlike clutter_actor_remove_all_children()
11814  * which will merely release the reference and remove each child.
11815  *
11816  * Unless you acquired an additional reference on each child of @self
11817  * prior to calling clutter_actor_remove_all_children() and want to reuse
11818  * the actors, you should use clutter_actor_destroy_all_children() in
11819  * order to make sure that children are destroyed and signal handlers
11820  * are disconnected even in cases where circular references prevent this
11821  * from automatically happening through reference counting alone.
11822  *
11823  * Since: 1.10
11824  */
11825 void
11826 clutter_actor_destroy_all_children (ClutterActor *self)
11827 {
11828   ClutterActorIter iter;
11829
11830   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11831
11832   if (self->priv->n_children == 0)
11833     return;
11834
11835   g_object_freeze_notify (G_OBJECT (self));
11836
11837   clutter_actor_iter_init (&iter, self);
11838   while (clutter_actor_iter_next (&iter, NULL))
11839     clutter_actor_iter_destroy (&iter);
11840
11841   g_object_thaw_notify (G_OBJECT (self));
11842
11843   /* sanity check */
11844   g_assert (self->priv->first_child == NULL);
11845   g_assert (self->priv->last_child == NULL);
11846   g_assert (self->priv->n_children == 0);
11847 }
11848
11849 typedef struct _InsertBetweenData {
11850   ClutterActor *prev_sibling;
11851   ClutterActor *next_sibling;
11852 } InsertBetweenData;
11853
11854 static void
11855 insert_child_between (ClutterActor *self,
11856                       ClutterActor *child,
11857                       gpointer      data_)
11858 {
11859   InsertBetweenData *data = data_;
11860   ClutterActor *prev_sibling = data->prev_sibling;
11861   ClutterActor *next_sibling = data->next_sibling;
11862
11863   child->priv->parent = self;
11864   child->priv->prev_sibling = prev_sibling;
11865   child->priv->next_sibling = next_sibling;
11866
11867   if (prev_sibling != NULL)
11868     prev_sibling->priv->next_sibling = child;
11869
11870   if (next_sibling != NULL)
11871     next_sibling->priv->prev_sibling = child;
11872
11873   if (child->priv->prev_sibling == NULL)
11874     self->priv->first_child = child;
11875
11876   if (child->priv->next_sibling == NULL)
11877     self->priv->last_child = child;
11878 }
11879
11880 /**
11881  * clutter_actor_replace_child:
11882  * @self: a #ClutterActor
11883  * @old_child: the child of @self to replace
11884  * @new_child: the #ClutterActor to replace @old_child
11885  *
11886  * Replaces @old_child with @new_child in the list of children of @self.
11887  *
11888  * Since: 1.10
11889  */
11890 void
11891 clutter_actor_replace_child (ClutterActor *self,
11892                              ClutterActor *old_child,
11893                              ClutterActor *new_child)
11894 {
11895   ClutterActor *prev_sibling, *next_sibling;
11896   InsertBetweenData clos;
11897
11898   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11899   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11900   g_return_if_fail (old_child->priv->parent == self);
11901   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11902   g_return_if_fail (old_child != new_child);
11903   g_return_if_fail (new_child != self);
11904   g_return_if_fail (new_child->priv->parent == NULL);
11905
11906   prev_sibling = old_child->priv->prev_sibling;
11907   next_sibling = old_child->priv->next_sibling;
11908   clutter_actor_remove_child_internal (self, old_child,
11909                                        REMOVE_CHILD_DEFAULT_FLAGS);
11910
11911   clos.prev_sibling = prev_sibling;
11912   clos.next_sibling = next_sibling;
11913   clutter_actor_add_child_internal (self, new_child,
11914                                     ADD_CHILD_DEFAULT_FLAGS,
11915                                     insert_child_between,
11916                                     &clos);
11917 }
11918
11919 /**
11920  * clutter_actor_unparent:
11921  * @self: a #ClutterActor
11922  *
11923  * Removes the parent of @self.
11924  *
11925  * This will cause the parent of @self to release the reference
11926  * acquired when calling clutter_actor_set_parent(), so if you
11927  * want to keep @self you will have to acquire a reference of
11928  * your own, through g_object_ref().
11929  *
11930  * This function should only be called by legacy #ClutterActor<!-- -->s
11931  * implementing the #ClutterContainer interface.
11932  *
11933  * Since: 0.1.1
11934  *
11935  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11936  */
11937 void
11938 clutter_actor_unparent (ClutterActor *self)
11939 {
11940   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11941
11942   if (self->priv->parent == NULL)
11943     return;
11944
11945   clutter_actor_remove_child_internal (self->priv->parent, self,
11946                                        REMOVE_CHILD_LEGACY_FLAGS);
11947 }
11948
11949 /**
11950  * clutter_actor_reparent:
11951  * @self: a #ClutterActor
11952  * @new_parent: the new #ClutterActor parent
11953  *
11954  * Resets the parent actor of @self.
11955  *
11956  * This function is logically equivalent to calling clutter_actor_unparent()
11957  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11958  * ensures the child is not finalized when unparented, and emits the
11959  * #ClutterActor::parent-set signal only once.
11960  *
11961  * In reality, calling this function is less useful than it sounds, as some
11962  * application code may rely on changes in the intermediate state between
11963  * removal and addition of the actor from its old parent to the @new_parent.
11964  * Thus, it is strongly encouraged to avoid using this function in application
11965  * code.
11966  *
11967  * Since: 0.2
11968  *
11969  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11970  *   clutter_actor_add_child() instead; remember to take a reference on
11971  *   the actor being removed before calling clutter_actor_remove_child()
11972  *   to avoid the reference count dropping to zero and the actor being
11973  *   destroyed.
11974  */
11975 void
11976 clutter_actor_reparent (ClutterActor *self,
11977                         ClutterActor *new_parent)
11978 {
11979   ClutterActorPrivate *priv;
11980
11981   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11982   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11983   g_return_if_fail (self != new_parent);
11984
11985   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11986     {
11987       g_warning ("Cannot set a parent on a toplevel actor");
11988       return;
11989     }
11990
11991   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11992     {
11993       g_warning ("Cannot set a parent currently being destroyed");
11994       return;
11995     }
11996
11997   priv = self->priv;
11998
11999   if (priv->parent != new_parent)
12000     {
12001       ClutterActor *old_parent;
12002
12003       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12004
12005       old_parent = priv->parent;
12006
12007       g_object_ref (self);
12008
12009       if (old_parent != NULL)
12010         {
12011          /* go through the Container implementation if this is a regular
12012           * child and not an internal one
12013           */
12014          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12015            {
12016              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
12017
12018              /* this will have to call unparent() */
12019              clutter_container_remove_actor (parent, self);
12020            }
12021          else
12022            clutter_actor_remove_child_internal (old_parent, self,
12023                                                 REMOVE_CHILD_LEGACY_FLAGS);
12024         }
12025
12026       /* Note, will call set_parent() */
12027       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12028         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
12029       else
12030         clutter_actor_add_child_internal (new_parent, self,
12031                                           ADD_CHILD_LEGACY_FLAGS,
12032                                           insert_child_at_depth,
12033                                           NULL);
12034
12035       /* we emit the ::parent-set signal once */
12036       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
12037
12038       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12039
12040       /* the IN_REPARENT flag suspends state updates */
12041       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
12042
12043       g_object_unref (self);
12044    }
12045 }
12046
12047 /**
12048  * clutter_actor_contains:
12049  * @self: A #ClutterActor
12050  * @descendant: A #ClutterActor, possibly contained in @self
12051  *
12052  * Determines if @descendant is contained inside @self (either as an
12053  * immediate child, or as a deeper descendant). If @self and
12054  * @descendant point to the same actor then it will also return %TRUE.
12055  *
12056  * Return value: whether @descendent is contained within @self
12057  *
12058  * Since: 1.4
12059  */
12060 gboolean
12061 clutter_actor_contains (ClutterActor *self,
12062                         ClutterActor *descendant)
12063 {
12064   ClutterActor *actor;
12065
12066   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12067   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
12068
12069   for (actor = descendant; actor; actor = actor->priv->parent)
12070     if (actor == self)
12071       return TRUE;
12072
12073   return FALSE;
12074 }
12075
12076 /**
12077  * clutter_actor_set_child_above_sibling:
12078  * @self: a #ClutterActor
12079  * @child: a #ClutterActor child of @self
12080  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12081  *
12082  * Sets @child to be above @sibling in the list of children of @self.
12083  *
12084  * If @sibling is %NULL, @child will be the new last child of @self.
12085  *
12086  * This function is logically equivalent to removing @child and using
12087  * clutter_actor_insert_child_above(), but it will not emit signals
12088  * or change state on @child.
12089  *
12090  * Since: 1.10
12091  */
12092 void
12093 clutter_actor_set_child_above_sibling (ClutterActor *self,
12094                                        ClutterActor *child,
12095                                        ClutterActor *sibling)
12096 {
12097   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12098   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12099   g_return_if_fail (child->priv->parent == self);
12100   g_return_if_fail (child != sibling);
12101   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12102
12103   if (sibling != NULL)
12104     g_return_if_fail (sibling->priv->parent == self);
12105
12106   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12107       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12108       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12109     return;
12110
12111   /* we don't want to change the state of child, or emit signals, or
12112    * regenerate ChildMeta instances here, but we still want to follow
12113    * the correct sequence of steps encoded in remove_child() and
12114    * add_child(), so that correctness is ensured, and we only go
12115    * through one known code path.
12116    */
12117   g_object_ref (child);
12118   clutter_actor_remove_child_internal (self, child, 0);
12119   clutter_actor_add_child_internal (self, child,
12120                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12121                                     insert_child_above,
12122                                     sibling);
12123
12124   clutter_actor_queue_relayout (self);
12125 }
12126
12127 /**
12128  * clutter_actor_set_child_below_sibling:
12129  * @self: a #ClutterActor
12130  * @child: a #ClutterActor child of @self
12131  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12132  *
12133  * Sets @child to be below @sibling in the list of children of @self.
12134  *
12135  * If @sibling is %NULL, @child will be the new first child of @self.
12136  *
12137  * This function is logically equivalent to removing @self and using
12138  * clutter_actor_insert_child_below(), but it will not emit signals
12139  * or change state on @child.
12140  *
12141  * Since: 1.10
12142  */
12143 void
12144 clutter_actor_set_child_below_sibling (ClutterActor *self,
12145                                        ClutterActor *child,
12146                                        ClutterActor *sibling)
12147 {
12148   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12149   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12150   g_return_if_fail (child->priv->parent == self);
12151   g_return_if_fail (child != sibling);
12152   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12153
12154   if (sibling != NULL)
12155     g_return_if_fail (sibling->priv->parent == self);
12156
12157   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12158       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12159       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12160     return;
12161
12162   /* see the comment in set_child_above_sibling() */
12163   g_object_ref (child);
12164   clutter_actor_remove_child_internal (self, child, 0);
12165   clutter_actor_add_child_internal (self, child,
12166                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12167                                     insert_child_below,
12168                                     sibling);
12169
12170   clutter_actor_queue_relayout (self);
12171 }
12172
12173 /**
12174  * clutter_actor_set_child_at_index:
12175  * @self: a #ClutterActor
12176  * @child: a #ClutterActor child of @self
12177  * @index_: the new index for @child
12178  *
12179  * Changes the index of @child in the list of children of @self.
12180  *
12181  * This function is logically equivalent to removing @child and
12182  * calling clutter_actor_insert_child_at_index(), but it will not
12183  * emit signals or change state on @child.
12184  *
12185  * Since: 1.10
12186  */
12187 void
12188 clutter_actor_set_child_at_index (ClutterActor *self,
12189                                   ClutterActor *child,
12190                                   gint          index_)
12191 {
12192   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12193   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12194   g_return_if_fail (child->priv->parent == self);
12195   g_return_if_fail (index_ <= self->priv->n_children);
12196
12197   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12198       CLUTTER_ACTOR_IN_DESTRUCTION (child))
12199     return;
12200
12201   g_object_ref (child);
12202   clutter_actor_remove_child_internal (self, child, 0);
12203   clutter_actor_add_child_internal (self, child,
12204                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12205                                     insert_child_at_index,
12206                                     GINT_TO_POINTER (index_));
12207
12208   clutter_actor_queue_relayout (self);
12209 }
12210
12211 /**
12212  * clutter_actor_raise:
12213  * @self: A #ClutterActor
12214  * @below: (allow-none): A #ClutterActor to raise above.
12215  *
12216  * Puts @self above @below.
12217  *
12218  * Both actors must have the same parent, and the parent must implement
12219  * the #ClutterContainer interface
12220  *
12221  * This function calls clutter_container_raise_child() internally.
12222  *
12223  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12224  */
12225 void
12226 clutter_actor_raise (ClutterActor *self,
12227                      ClutterActor *below)
12228 {
12229   ClutterActor *parent;
12230
12231   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12232
12233   parent = clutter_actor_get_parent (self);
12234   if (parent == NULL)
12235     {
12236       g_warning ("%s: Actor '%s' is not inside a container",
12237                  G_STRFUNC,
12238                  _clutter_actor_get_debug_name (self));
12239       return;
12240     }
12241
12242   if (below != NULL)
12243     {
12244       if (parent != clutter_actor_get_parent (below))
12245         {
12246           g_warning ("%s Actor '%s' is not in the same container as "
12247                      "actor '%s'",
12248                      G_STRFUNC,
12249                      _clutter_actor_get_debug_name (self),
12250                      _clutter_actor_get_debug_name (below));
12251           return;
12252         }
12253     }
12254
12255   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12256 }
12257
12258 /**
12259  * clutter_actor_lower:
12260  * @self: A #ClutterActor
12261  * @above: (allow-none): A #ClutterActor to lower below
12262  *
12263  * Puts @self below @above.
12264  *
12265  * Both actors must have the same parent, and the parent must implement
12266  * the #ClutterContainer interface.
12267  *
12268  * This function calls clutter_container_lower_child() internally.
12269  *
12270  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12271  */
12272 void
12273 clutter_actor_lower (ClutterActor *self,
12274                      ClutterActor *above)
12275 {
12276   ClutterActor *parent;
12277
12278   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12279
12280   parent = clutter_actor_get_parent (self);
12281   if (parent == NULL)
12282     {
12283       g_warning ("%s: Actor of type %s is not inside a container",
12284                  G_STRFUNC,
12285                  _clutter_actor_get_debug_name (self));
12286       return;
12287     }
12288
12289   if (above)
12290     {
12291       if (parent != clutter_actor_get_parent (above))
12292         {
12293           g_warning ("%s: Actor '%s' is not in the same container as "
12294                      "actor '%s'",
12295                      G_STRFUNC,
12296                      _clutter_actor_get_debug_name (self),
12297                      _clutter_actor_get_debug_name (above));
12298           return;
12299         }
12300     }
12301
12302   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12303 }
12304
12305 /**
12306  * clutter_actor_raise_top:
12307  * @self: A #ClutterActor
12308  *
12309  * Raises @self to the top.
12310  *
12311  * This function calls clutter_actor_raise() internally.
12312  *
12313  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12314  *   a %NULL sibling, instead.
12315  */
12316 void
12317 clutter_actor_raise_top (ClutterActor *self)
12318 {
12319   clutter_actor_raise (self, NULL);
12320 }
12321
12322 /**
12323  * clutter_actor_lower_bottom:
12324  * @self: A #ClutterActor
12325  *
12326  * Lowers @self to the bottom.
12327  *
12328  * This function calls clutter_actor_lower() internally.
12329  *
12330  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12331  *   a %NULL sibling, instead.
12332  */
12333 void
12334 clutter_actor_lower_bottom (ClutterActor *self)
12335 {
12336   clutter_actor_lower (self, NULL);
12337 }
12338
12339 /*
12340  * Event handling
12341  */
12342
12343 /**
12344  * clutter_actor_event:
12345  * @actor: a #ClutterActor
12346  * @event: a #ClutterEvent
12347  * @capture: TRUE if event in in capture phase, FALSE otherwise.
12348  *
12349  * This function is used to emit an event on the main stage.
12350  * You should rarely need to use this function, except for
12351  * synthetising events.
12352  *
12353  * Return value: the return value from the signal emission: %TRUE
12354  *   if the actor handled the event, or %FALSE if the event was
12355  *   not handled
12356  *
12357  * Since: 0.6
12358  */
12359 gboolean
12360 clutter_actor_event (ClutterActor *actor,
12361                      ClutterEvent *event,
12362                      gboolean      capture)
12363 {
12364   gboolean retval = FALSE;
12365   gint signal_num = -1;
12366
12367   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12368   g_return_val_if_fail (event != NULL, FALSE);
12369
12370   g_object_ref (actor);
12371
12372   if (capture)
12373     {
12374       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12375                      event,
12376                      &retval);
12377       goto out;
12378     }
12379
12380   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12381
12382   if (!retval)
12383     {
12384       switch (event->type)
12385         {
12386         case CLUTTER_NOTHING:
12387           break;
12388         case CLUTTER_BUTTON_PRESS:
12389           signal_num = BUTTON_PRESS_EVENT;
12390           break;
12391         case CLUTTER_BUTTON_RELEASE:
12392           signal_num = BUTTON_RELEASE_EVENT;
12393           break;
12394         case CLUTTER_SCROLL:
12395           signal_num = SCROLL_EVENT;
12396           break;
12397         case CLUTTER_KEY_PRESS:
12398           signal_num = KEY_PRESS_EVENT;
12399           break;
12400         case CLUTTER_KEY_RELEASE:
12401           signal_num = KEY_RELEASE_EVENT;
12402           break;
12403         case CLUTTER_MOTION:
12404           signal_num = MOTION_EVENT;
12405           break;
12406         case CLUTTER_ENTER:
12407           signal_num = ENTER_EVENT;
12408           break;
12409         case CLUTTER_LEAVE:
12410           signal_num = LEAVE_EVENT;
12411           break;
12412         case CLUTTER_DELETE:
12413         case CLUTTER_DESTROY_NOTIFY:
12414         case CLUTTER_CLIENT_MESSAGE:
12415         default:
12416           signal_num = -1;
12417           break;
12418         }
12419
12420       if (signal_num != -1)
12421         g_signal_emit (actor, actor_signals[signal_num], 0,
12422                        event, &retval);
12423     }
12424
12425 out:
12426   g_object_unref (actor);
12427
12428   return retval;
12429 }
12430
12431 /**
12432  * clutter_actor_set_reactive:
12433  * @actor: a #ClutterActor
12434  * @reactive: whether the actor should be reactive to events
12435  *
12436  * Sets @actor as reactive. Reactive actors will receive events.
12437  *
12438  * Since: 0.6
12439  */
12440 void
12441 clutter_actor_set_reactive (ClutterActor *actor,
12442                             gboolean      reactive)
12443 {
12444   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12445
12446   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12447     return;
12448
12449   if (reactive)
12450     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12451   else
12452     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12453
12454   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12455 }
12456
12457 /**
12458  * clutter_actor_get_reactive:
12459  * @actor: a #ClutterActor
12460  *
12461  * Checks whether @actor is marked as reactive.
12462  *
12463  * Return value: %TRUE if the actor is reactive
12464  *
12465  * Since: 0.6
12466  */
12467 gboolean
12468 clutter_actor_get_reactive (ClutterActor *actor)
12469 {
12470   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12471
12472   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12473 }
12474
12475 /**
12476  * clutter_actor_get_anchor_point:
12477  * @self: a #ClutterActor
12478  * @anchor_x: (out): return location for the X coordinate of the anchor point
12479  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12480  *
12481  * Gets the current anchor point of the @actor in pixels.
12482  *
12483  * Since: 0.6
12484  */
12485 void
12486 clutter_actor_get_anchor_point (ClutterActor *self,
12487                                 gfloat       *anchor_x,
12488                                 gfloat       *anchor_y)
12489 {
12490   const ClutterTransformInfo *info;
12491
12492   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12493
12494   info = _clutter_actor_get_transform_info_or_defaults (self);
12495   clutter_anchor_coord_get_units (self, &info->anchor,
12496                                   anchor_x,
12497                                   anchor_y,
12498                                   NULL);
12499 }
12500
12501 /**
12502  * clutter_actor_set_anchor_point:
12503  * @self: a #ClutterActor
12504  * @anchor_x: X coordinate of the anchor point
12505  * @anchor_y: Y coordinate of the anchor point
12506  *
12507  * Sets an anchor point for @self. The anchor point is a point in the
12508  * coordinate space of an actor to which the actor position within its
12509  * parent is relative; the default is (0, 0), i.e. the top-left corner
12510  * of the actor.
12511  *
12512  * Since: 0.6
12513  */
12514 void
12515 clutter_actor_set_anchor_point (ClutterActor *self,
12516                                 gfloat        anchor_x,
12517                                 gfloat        anchor_y)
12518 {
12519   ClutterTransformInfo *info;
12520   ClutterActorPrivate *priv;
12521   gboolean changed = FALSE;
12522   gfloat old_anchor_x, old_anchor_y;
12523   GObject *obj;
12524
12525   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12526
12527   obj = G_OBJECT (self);
12528   priv = self->priv;
12529   info = _clutter_actor_get_transform_info (self);
12530
12531   g_object_freeze_notify (obj);
12532
12533   clutter_anchor_coord_get_units (self, &info->anchor,
12534                                   &old_anchor_x,
12535                                   &old_anchor_y,
12536                                   NULL);
12537
12538   if (info->anchor.is_fractional)
12539     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12540
12541   if (old_anchor_x != anchor_x)
12542     {
12543       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12544       changed = TRUE;
12545     }
12546
12547   if (old_anchor_y != anchor_y)
12548     {
12549       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12550       changed = TRUE;
12551     }
12552
12553   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12554
12555   if (changed)
12556     {
12557       priv->transform_valid = FALSE;
12558       clutter_actor_queue_redraw (self);
12559     }
12560
12561   g_object_thaw_notify (obj);
12562 }
12563
12564 /**
12565  * clutter_actor_get_anchor_point_gravity:
12566  * @self: a #ClutterActor
12567  *
12568  * Retrieves the anchor position expressed as a #ClutterGravity. If
12569  * the anchor point was specified using pixels or units this will
12570  * return %CLUTTER_GRAVITY_NONE.
12571  *
12572  * Return value: the #ClutterGravity used by the anchor point
12573  *
12574  * Since: 1.0
12575  */
12576 ClutterGravity
12577 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12578 {
12579   const ClutterTransformInfo *info;
12580
12581   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12582
12583   info = _clutter_actor_get_transform_info_or_defaults (self);
12584
12585   return clutter_anchor_coord_get_gravity (&info->anchor);
12586 }
12587
12588 /**
12589  * clutter_actor_move_anchor_point:
12590  * @self: a #ClutterActor
12591  * @anchor_x: X coordinate of the anchor point
12592  * @anchor_y: Y coordinate of the anchor point
12593  *
12594  * Sets an anchor point for the actor, and adjusts the actor postion so that
12595  * the relative position of the actor toward its parent remains the same.
12596  *
12597  * Since: 0.6
12598  */
12599 void
12600 clutter_actor_move_anchor_point (ClutterActor *self,
12601                                  gfloat        anchor_x,
12602                                  gfloat        anchor_y)
12603 {
12604   gfloat old_anchor_x, old_anchor_y;
12605   const ClutterTransformInfo *info;
12606
12607   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12608
12609   info = _clutter_actor_get_transform_info (self);
12610   clutter_anchor_coord_get_units (self, &info->anchor,
12611                                   &old_anchor_x,
12612                                   &old_anchor_y,
12613                                   NULL);
12614
12615   g_object_freeze_notify (G_OBJECT (self));
12616
12617   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12618
12619   if (self->priv->position_set)
12620     clutter_actor_move_by (self,
12621                            anchor_x - old_anchor_x,
12622                            anchor_y - old_anchor_y);
12623
12624   g_object_thaw_notify (G_OBJECT (self));
12625 }
12626
12627 /**
12628  * clutter_actor_move_anchor_point_from_gravity:
12629  * @self: a #ClutterActor
12630  * @gravity: #ClutterGravity.
12631  *
12632  * Sets an anchor point on the actor based on the given gravity, adjusting the
12633  * actor postion so that its relative position within its parent remains
12634  * unchanged.
12635  *
12636  * Since version 1.0 the anchor point will be stored as a gravity so
12637  * that if the actor changes size then the anchor point will move. For
12638  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12639  * and later double the size of the actor, the anchor point will move
12640  * to the bottom right.
12641  *
12642  * Since: 0.6
12643  */
12644 void
12645 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12646                                               ClutterGravity  gravity)
12647 {
12648   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12649   const ClutterTransformInfo *info;
12650   ClutterActorPrivate *priv;
12651
12652   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12653
12654   priv = self->priv;
12655   info = _clutter_actor_get_transform_info (self);
12656
12657   g_object_freeze_notify (G_OBJECT (self));
12658
12659   clutter_anchor_coord_get_units (self, &info->anchor,
12660                                   &old_anchor_x,
12661                                   &old_anchor_y,
12662                                   NULL);
12663   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12664   clutter_anchor_coord_get_units (self, &info->anchor,
12665                                   &new_anchor_x,
12666                                   &new_anchor_y,
12667                                   NULL);
12668
12669   if (priv->position_set)
12670     clutter_actor_move_by (self,
12671                            new_anchor_x - old_anchor_x,
12672                            new_anchor_y - old_anchor_y);
12673
12674   g_object_thaw_notify (G_OBJECT (self));
12675 }
12676
12677 /**
12678  * clutter_actor_set_anchor_point_from_gravity:
12679  * @self: a #ClutterActor
12680  * @gravity: #ClutterGravity.
12681  *
12682  * Sets an anchor point on the actor, based on the given gravity (this is a
12683  * convenience function wrapping clutter_actor_set_anchor_point()).
12684  *
12685  * Since version 1.0 the anchor point will be stored as a gravity so
12686  * that if the actor changes size then the anchor point will move. For
12687  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12688  * and later double the size of the actor, the anchor point will move
12689  * to the bottom right.
12690  *
12691  * Since: 0.6
12692  */
12693 void
12694 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12695                                              ClutterGravity  gravity)
12696 {
12697   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12698
12699   if (gravity == CLUTTER_GRAVITY_NONE)
12700     clutter_actor_set_anchor_point (self, 0, 0);
12701   else
12702     {
12703       GObject *obj = G_OBJECT (self);
12704       ClutterTransformInfo *info;
12705
12706       g_object_freeze_notify (obj);
12707
12708       info = _clutter_actor_get_transform_info (self);
12709       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12710
12711       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12712       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12713       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12714
12715       self->priv->transform_valid = FALSE;
12716
12717       clutter_actor_queue_redraw (self);
12718
12719       g_object_thaw_notify (obj);
12720     }
12721 }
12722
12723 static void
12724 clutter_actor_store_content_box (ClutterActor *self,
12725                                  const ClutterActorBox *box)
12726 {
12727   if (box != NULL)
12728     {
12729       self->priv->content_box = *box;
12730       self->priv->content_box_valid = TRUE;
12731     }
12732   else
12733     self->priv->content_box_valid = FALSE;
12734
12735   clutter_actor_queue_redraw (self);
12736
12737   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12738 }
12739
12740 static void
12741 clutter_container_iface_init (ClutterContainerIface *iface)
12742 {
12743   /* we don't override anything, as ClutterContainer already has a default
12744    * implementation that we can use, and which calls into our own API.
12745    */
12746 }
12747
12748 typedef enum
12749 {
12750   PARSE_X,
12751   PARSE_Y,
12752   PARSE_WIDTH,
12753   PARSE_HEIGHT,
12754   PARSE_ANCHOR_X,
12755   PARSE_ANCHOR_Y
12756 } ParseDimension;
12757
12758 static gfloat
12759 parse_units (ClutterActor   *self,
12760              ParseDimension  dimension,
12761              JsonNode       *node)
12762 {
12763   GValue value = G_VALUE_INIT;
12764   gfloat retval = 0;
12765
12766   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12767     return 0;
12768
12769   json_node_get_value (node, &value);
12770
12771   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12772     {
12773       retval = (gfloat) g_value_get_int64 (&value);
12774     }
12775   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12776     {
12777       retval = g_value_get_double (&value);
12778     }
12779   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12780     {
12781       ClutterUnits units;
12782       gboolean res;
12783
12784       res = clutter_units_from_string (&units, g_value_get_string (&value));
12785       if (res)
12786         retval = clutter_units_to_pixels (&units);
12787       else
12788         {
12789           g_warning ("Invalid value '%s': integers, strings or floating point "
12790                      "values can be used for the x, y, width and height "
12791                      "properties. Valid modifiers for strings are 'px', 'mm', "
12792                      "'pt' and 'em'.",
12793                      g_value_get_string (&value));
12794           retval = 0;
12795         }
12796     }
12797   else
12798     {
12799       g_warning ("Invalid value of type '%s': integers, strings of floating "
12800                  "point values can be used for the x, y, width, height "
12801                  "anchor-x and anchor-y properties.",
12802                  g_type_name (G_VALUE_TYPE (&value)));
12803     }
12804
12805   g_value_unset (&value);
12806
12807   return retval;
12808 }
12809
12810 typedef struct {
12811   ClutterRotateAxis axis;
12812
12813   gdouble angle;
12814
12815   gfloat center_x;
12816   gfloat center_y;
12817   gfloat center_z;
12818 } RotationInfo;
12819
12820 static inline gboolean
12821 parse_rotation_array (ClutterActor *actor,
12822                       JsonArray    *array,
12823                       RotationInfo *info)
12824 {
12825   JsonNode *element;
12826
12827   if (json_array_get_length (array) != 2)
12828     return FALSE;
12829
12830   /* angle */
12831   element = json_array_get_element (array, 0);
12832   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12833     info->angle = json_node_get_double (element);
12834   else
12835     return FALSE;
12836
12837   /* center */
12838   element = json_array_get_element (array, 1);
12839   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12840     {
12841       JsonArray *center = json_node_get_array (element);
12842
12843       if (json_array_get_length (center) != 2)
12844         return FALSE;
12845
12846       switch (info->axis)
12847         {
12848         case CLUTTER_X_AXIS:
12849           info->center_y = parse_units (actor, PARSE_Y,
12850                                         json_array_get_element (center, 0));
12851           info->center_z = parse_units (actor, PARSE_Y,
12852                                         json_array_get_element (center, 1));
12853           return TRUE;
12854
12855         case CLUTTER_Y_AXIS:
12856           info->center_x = parse_units (actor, PARSE_X,
12857                                         json_array_get_element (center, 0));
12858           info->center_z = parse_units (actor, PARSE_X,
12859                                         json_array_get_element (center, 1));
12860           return TRUE;
12861
12862         case CLUTTER_Z_AXIS:
12863           info->center_x = parse_units (actor, PARSE_X,
12864                                         json_array_get_element (center, 0));
12865           info->center_y = parse_units (actor, PARSE_Y,
12866                                         json_array_get_element (center, 1));
12867           return TRUE;
12868         }
12869     }
12870
12871   return FALSE;
12872 }
12873
12874 static gboolean
12875 parse_rotation (ClutterActor *actor,
12876                 JsonNode     *node,
12877                 RotationInfo *info)
12878 {
12879   JsonArray *array;
12880   guint len, i;
12881   gboolean retval = FALSE;
12882
12883   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12884     {
12885       g_warning ("Invalid node of type '%s' found, expecting an array",
12886                  json_node_type_name (node));
12887       return FALSE;
12888     }
12889
12890   array = json_node_get_array (node);
12891   len = json_array_get_length (array);
12892
12893   for (i = 0; i < len; i++)
12894     {
12895       JsonNode *element = json_array_get_element (array, i);
12896       JsonObject *object;
12897       JsonNode *member;
12898
12899       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12900         {
12901           g_warning ("Invalid node of type '%s' found, expecting an object",
12902                      json_node_type_name (element));
12903           return FALSE;
12904         }
12905
12906       object = json_node_get_object (element);
12907
12908       if (json_object_has_member (object, "x-axis"))
12909         {
12910           member = json_object_get_member (object, "x-axis");
12911
12912           info->axis = CLUTTER_X_AXIS;
12913
12914           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12915             {
12916               info->angle = json_node_get_double (member);
12917               retval = TRUE;
12918             }
12919           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12920             retval = parse_rotation_array (actor,
12921                                            json_node_get_array (member),
12922                                            info);
12923           else
12924             retval = FALSE;
12925         }
12926       else if (json_object_has_member (object, "y-axis"))
12927         {
12928           member = json_object_get_member (object, "y-axis");
12929
12930           info->axis = CLUTTER_Y_AXIS;
12931
12932           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12933             {
12934               info->angle = json_node_get_double (member);
12935               retval = TRUE;
12936             }
12937           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12938             retval = parse_rotation_array (actor,
12939                                            json_node_get_array (member),
12940                                            info);
12941           else
12942             retval = FALSE;
12943         }
12944       else if (json_object_has_member (object, "z-axis"))
12945         {
12946           member = json_object_get_member (object, "z-axis");
12947
12948           info->axis = CLUTTER_Z_AXIS;
12949
12950           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12951             {
12952               info->angle = json_node_get_double (member);
12953               retval = TRUE;
12954             }
12955           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12956             retval = parse_rotation_array (actor,
12957                                            json_node_get_array (member),
12958                                            info);
12959           else
12960             retval = FALSE;
12961         }
12962     }
12963
12964   return retval;
12965 }
12966
12967 static GSList *
12968 parse_actor_metas (ClutterScript *script,
12969                    ClutterActor  *actor,
12970                    JsonNode      *node)
12971 {
12972   GList *elements, *l;
12973   GSList *retval = NULL;
12974
12975   if (!JSON_NODE_HOLDS_ARRAY (node))
12976     return NULL;
12977
12978   elements = json_array_get_elements (json_node_get_array (node));
12979
12980   for (l = elements; l != NULL; l = l->next)
12981     {
12982       JsonNode *element = l->data;
12983       const gchar *id_ = _clutter_script_get_id_from_node (element);
12984       GObject *meta;
12985
12986       if (id_ == NULL || *id_ == '\0')
12987         continue;
12988
12989       meta = clutter_script_get_object (script, id_);
12990       if (meta == NULL)
12991         continue;
12992
12993       retval = g_slist_prepend (retval, meta);
12994     }
12995
12996   g_list_free (elements);
12997
12998   return g_slist_reverse (retval);
12999 }
13000
13001 static GSList *
13002 parse_behaviours (ClutterScript *script,
13003                   ClutterActor  *actor,
13004                   JsonNode      *node)
13005 {
13006   GList *elements, *l;
13007   GSList *retval = NULL;
13008
13009   if (!JSON_NODE_HOLDS_ARRAY (node))
13010     return NULL;
13011
13012   elements = json_array_get_elements (json_node_get_array (node));
13013
13014   for (l = elements; l != NULL; l = l->next)
13015     {
13016       JsonNode *element = l->data;
13017       const gchar *id_ = _clutter_script_get_id_from_node (element);
13018       GObject *behaviour;
13019
13020       if (id_ == NULL || *id_ == '\0')
13021         continue;
13022
13023       behaviour = clutter_script_get_object (script, id_);
13024       if (behaviour == NULL)
13025         continue;
13026
13027       retval = g_slist_prepend (retval, behaviour);
13028     }
13029
13030   g_list_free (elements);
13031
13032   return g_slist_reverse (retval);
13033 }
13034
13035 static ClutterMargin *
13036 parse_margin (ClutterActor *self,
13037               JsonNode     *node)
13038 {
13039   ClutterMargin *margin;
13040   JsonArray *array;
13041
13042   if (!JSON_NODE_HOLDS_ARRAY (node))
13043     {
13044       g_warning ("The margin property must be an array of 1 to 4 elements");
13045       return NULL;
13046     }
13047
13048   margin = clutter_margin_new ();
13049   array = json_node_get_array (node);
13050   switch (json_array_get_length (array))
13051     {
13052     case 1:
13053       margin->top = margin->right = margin->bottom = margin->left =
13054         parse_units (self, 0, json_array_get_element (array, 0));
13055       break;
13056
13057     case 2:
13058       margin->top = margin->bottom =
13059         parse_units (self, 0, json_array_get_element (array, 0));
13060       margin->right = margin->left =
13061         parse_units (self, 0, json_array_get_element (array, 1));
13062       break;
13063
13064     case 3:
13065       margin->top =
13066         parse_units (self, 0, json_array_get_element (array, 0));
13067       margin->right = margin->left =
13068         parse_units (self, 0, json_array_get_element (array, 1));
13069       margin->bottom =
13070         parse_units (self, 0, json_array_get_element (array, 2));
13071       break;
13072
13073     case 4:
13074       margin->top =
13075         parse_units (self, 0, json_array_get_element (array, 0));
13076       margin->right =
13077         parse_units (self, 0, json_array_get_element (array, 1));
13078       margin->bottom =
13079         parse_units (self, 0, json_array_get_element (array, 2));
13080       margin->left =
13081         parse_units (self, 0, json_array_get_element (array, 3));
13082       break;
13083
13084     default:
13085       g_warning ("The margin property must be an array of 1 to 4 elements");
13086       clutter_margin_free (margin);
13087       return NULL;
13088     }
13089   return margin;
13090 }
13091
13092 static gboolean
13093 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
13094                                  ClutterScript     *script,
13095                                  GValue            *value,
13096                                  const gchar       *name,
13097                                  JsonNode          *node)
13098 {
13099   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13100   gboolean retval = FALSE;
13101
13102   if ((name[0] == 'x' && name[1] == '\0') ||
13103       (name[0] == 'y' && name[1] == '\0') ||
13104       (strcmp (name, "width") == 0) ||
13105       (strcmp (name, "height") == 0) ||
13106       (strcmp (name, "anchor_x") == 0) ||
13107       (strcmp (name, "anchor_y") == 0))
13108     {
13109       ParseDimension dimension;
13110       gfloat units;
13111
13112       if (name[0] == 'x')
13113         dimension = PARSE_X;
13114       else if (name[0] == 'y')
13115         dimension = PARSE_Y;
13116       else if (name[0] == 'w')
13117         dimension = PARSE_WIDTH;
13118       else if (name[0] == 'h')
13119         dimension = PARSE_HEIGHT;
13120       else if (name[0] == 'a' && name[7] == 'x')
13121         dimension = PARSE_ANCHOR_X;
13122       else if (name[0] == 'a' && name[7] == 'y')
13123         dimension = PARSE_ANCHOR_Y;
13124       else
13125         return FALSE;
13126
13127       units = parse_units (actor, dimension, node);
13128
13129       /* convert back to pixels: all properties are pixel-based */
13130       g_value_init (value, G_TYPE_FLOAT);
13131       g_value_set_float (value, units);
13132
13133       retval = TRUE;
13134     }
13135   else if (strcmp (name, "rotation") == 0)
13136     {
13137       RotationInfo *info;
13138
13139       info = g_slice_new0 (RotationInfo);
13140       retval = parse_rotation (actor, node, info);
13141
13142       if (retval)
13143         {
13144           g_value_init (value, G_TYPE_POINTER);
13145           g_value_set_pointer (value, info);
13146         }
13147       else
13148         g_slice_free (RotationInfo, info);
13149     }
13150   else if (strcmp (name, "behaviours") == 0)
13151     {
13152       GSList *l;
13153
13154 #ifdef CLUTTER_ENABLE_DEBUG
13155       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
13156         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
13157                                      "and it should not be used in newly "
13158                                      "written ClutterScript definitions.");
13159 #endif
13160
13161       l = parse_behaviours (script, actor, node);
13162
13163       g_value_init (value, G_TYPE_POINTER);
13164       g_value_set_pointer (value, l);
13165
13166       retval = TRUE;
13167     }
13168   else if (strcmp (name, "actions") == 0 ||
13169            strcmp (name, "constraints") == 0 ||
13170            strcmp (name, "effects") == 0)
13171     {
13172       GSList *l;
13173
13174       l = parse_actor_metas (script, actor, node);
13175
13176       g_value_init (value, G_TYPE_POINTER);
13177       g_value_set_pointer (value, l);
13178
13179       retval = TRUE;
13180     }
13181   else if (strcmp (name, "margin") == 0)
13182     {
13183       ClutterMargin *margin = parse_margin (actor, node);
13184
13185       if (margin)
13186         {
13187           g_value_init (value, CLUTTER_TYPE_MARGIN);
13188           g_value_set_boxed (value, margin);
13189           retval = TRUE;
13190         }
13191     }
13192
13193   return retval;
13194 }
13195
13196 static void
13197 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
13198                                    ClutterScript     *script,
13199                                    const gchar       *name,
13200                                    const GValue      *value)
13201 {
13202   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13203
13204 #ifdef CLUTTER_ENABLE_DEBUG
13205   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
13206     {
13207       gchar *tmp = g_strdup_value_contents (value);
13208
13209       CLUTTER_NOTE (SCRIPT,
13210                     "in ClutterActor::set_custom_property('%s') = %s",
13211                     name,
13212                     tmp);
13213
13214       g_free (tmp);
13215     }
13216 #endif /* CLUTTER_ENABLE_DEBUG */
13217
13218   if (strcmp (name, "rotation") == 0)
13219     {
13220       RotationInfo *info;
13221
13222       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13223         return;
13224
13225       info = g_value_get_pointer (value);
13226
13227       clutter_actor_set_rotation (actor,
13228                                   info->axis, info->angle,
13229                                   info->center_x,
13230                                   info->center_y,
13231                                   info->center_z);
13232
13233       g_slice_free (RotationInfo, info);
13234
13235       return;
13236     }
13237
13238   if (strcmp (name, "behaviours") == 0)
13239     {
13240       GSList *behaviours, *l;
13241
13242       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13243         return;
13244
13245       behaviours = g_value_get_pointer (value);
13246       for (l = behaviours; l != NULL; l = l->next)
13247         {
13248           ClutterBehaviour *behaviour = l->data;
13249
13250           clutter_behaviour_apply (behaviour, actor);
13251         }
13252
13253       g_slist_free (behaviours);
13254
13255       return;
13256     }
13257
13258   if (strcmp (name, "actions") == 0 ||
13259       strcmp (name, "constraints") == 0 ||
13260       strcmp (name, "effects") == 0)
13261     {
13262       GSList *metas, *l;
13263
13264       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13265         return;
13266
13267       metas = g_value_get_pointer (value);
13268       for (l = metas; l != NULL; l = l->next)
13269         {
13270           if (name[0] == 'a')
13271             clutter_actor_add_action (actor, l->data);
13272
13273           if (name[0] == 'c')
13274             clutter_actor_add_constraint (actor, l->data);
13275
13276           if (name[0] == 'e')
13277             clutter_actor_add_effect (actor, l->data);
13278         }
13279
13280       g_slist_free (metas);
13281
13282       return;
13283     }
13284   if (strcmp (name, "margin") == 0)
13285     {
13286       clutter_actor_set_margin (actor, g_value_get_boxed (value));
13287       return;
13288     }
13289
13290   g_object_set_property (G_OBJECT (scriptable), name, value);
13291 }
13292
13293 static void
13294 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13295 {
13296   iface->parse_custom_node = clutter_actor_parse_custom_node;
13297   iface->set_custom_property = clutter_actor_set_custom_property;
13298 }
13299
13300 static ClutterActorMeta *
13301 get_meta_from_animation_property (ClutterActor  *actor,
13302                                   const gchar   *name,
13303                                   gchar        **name_p)
13304 {
13305   ClutterActorPrivate *priv = actor->priv;
13306   ClutterActorMeta *meta = NULL;
13307   gchar **tokens;
13308
13309   /* if this is not a special property, fall through */
13310   if (name[0] != '@')
13311     return NULL;
13312
13313   /* detect the properties named using the following spec:
13314    *
13315    *   @<section>.<meta-name>.<property-name>
13316    *
13317    * where <section> can be one of the following:
13318    *
13319    *   - actions
13320    *   - constraints
13321    *   - effects
13322    *
13323    * and <meta-name> is the name set on a specific ActorMeta
13324    */
13325
13326   tokens = g_strsplit (name + 1, ".", -1);
13327   if (tokens == NULL || g_strv_length (tokens) != 3)
13328     {
13329       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13330                     name + 1);
13331       g_strfreev (tokens);
13332       return NULL;
13333     }
13334
13335   if (strcmp (tokens[0], "actions") == 0)
13336     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13337
13338   if (strcmp (tokens[0], "constraints") == 0)
13339     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13340
13341   if (strcmp (tokens[0], "effects") == 0)
13342     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13343
13344   if (name_p != NULL)
13345     *name_p = g_strdup (tokens[2]);
13346
13347   CLUTTER_NOTE (ANIMATION,
13348                 "Looking for property '%s' of object '%s' in section '%s'",
13349                 tokens[2],
13350                 tokens[1],
13351                 tokens[0]);
13352
13353   g_strfreev (tokens);
13354
13355   return meta;
13356 }
13357
13358 static GParamSpec *
13359 clutter_actor_find_property (ClutterAnimatable *animatable,
13360                              const gchar       *property_name)
13361 {
13362   ClutterActorMeta *meta = NULL;
13363   GObjectClass *klass = NULL;
13364   GParamSpec *pspec = NULL;
13365   gchar *p_name = NULL;
13366
13367   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13368                                            property_name,
13369                                            &p_name);
13370
13371   if (meta != NULL)
13372     {
13373       klass = G_OBJECT_GET_CLASS (meta);
13374
13375       pspec = g_object_class_find_property (klass, p_name);
13376     }
13377   else
13378     {
13379       klass = G_OBJECT_GET_CLASS (animatable);
13380
13381       pspec = g_object_class_find_property (klass, property_name);
13382     }
13383
13384   g_free (p_name);
13385
13386   return pspec;
13387 }
13388
13389 static void
13390 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13391                                  const gchar       *property_name,
13392                                  GValue            *initial)
13393 {
13394   ClutterActorMeta *meta = NULL;
13395   gchar *p_name = NULL;
13396
13397   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13398                                            property_name,
13399                                            &p_name);
13400
13401   if (meta != NULL)
13402     g_object_get_property (G_OBJECT (meta), p_name, initial);
13403   else
13404     g_object_get_property (G_OBJECT (animatable), property_name, initial);
13405
13406   g_free (p_name);
13407 }
13408
13409 /*
13410  * clutter_actor_set_animatable_property:
13411  * @actor: a #ClutterActor
13412  * @prop_id: the paramspec id
13413  * @value: the value to set
13414  * @pspec: the paramspec
13415  *
13416  * Sets values of animatable properties.
13417  *
13418  * This is a variant of clutter_actor_set_property() that gets called
13419  * by the #ClutterAnimatable implementation of #ClutterActor for the
13420  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13421  * #GParamSpec.
13422  *
13423  * Unlike the implementation of #GObjectClass.set_property(), this
13424  * function will not update the interval if a transition involving an
13425  * animatable property is in progress - this avoids cycles with the
13426  * transition API calling the public API.
13427  */
13428 static void
13429 clutter_actor_set_animatable_property (ClutterActor *actor,
13430                                        guint         prop_id,
13431                                        const GValue *value,
13432                                        GParamSpec   *pspec)
13433 {
13434   GObject *obj = G_OBJECT (actor);
13435
13436   g_object_freeze_notify (obj);
13437
13438   switch (prop_id)
13439     {
13440     case PROP_X:
13441       clutter_actor_set_x_internal (actor, g_value_get_float (value));
13442       break;
13443
13444     case PROP_Y:
13445       clutter_actor_set_y_internal (actor, g_value_get_float (value));
13446       break;
13447
13448     case PROP_POSITION:
13449       clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13450       break;
13451
13452     case PROP_WIDTH:
13453       clutter_actor_set_width_internal (actor, g_value_get_float (value));
13454       break;
13455
13456     case PROP_HEIGHT:
13457       clutter_actor_set_height_internal (actor, g_value_get_float (value));
13458       break;
13459
13460     case PROP_SIZE:
13461       clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13462       break;
13463
13464     case PROP_ALLOCATION:
13465       clutter_actor_allocate_internal (actor,
13466                                        g_value_get_boxed (value),
13467                                        actor->priv->allocation_flags);
13468       break;
13469
13470     case PROP_DEPTH:
13471       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13472       break;
13473
13474     case PROP_OPACITY:
13475       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13476       break;
13477
13478     case PROP_BACKGROUND_COLOR:
13479       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13480       break;
13481
13482     case PROP_SCALE_X:
13483       clutter_actor_set_scale_factor_internal (actor,
13484                                                g_value_get_double (value),
13485                                                pspec);
13486       break;
13487
13488     case PROP_SCALE_Y:
13489       clutter_actor_set_scale_factor_internal (actor,
13490                                                g_value_get_double (value),
13491                                                pspec);
13492       break;
13493
13494     case PROP_ROTATION_ANGLE_X:
13495       clutter_actor_set_rotation_angle_internal (actor,
13496                                                  CLUTTER_X_AXIS,
13497                                                  g_value_get_double (value));
13498       break;
13499
13500     case PROP_ROTATION_ANGLE_Y:
13501       clutter_actor_set_rotation_angle_internal (actor,
13502                                                  CLUTTER_Y_AXIS,
13503                                                  g_value_get_double (value));
13504       break;
13505
13506     case PROP_ROTATION_ANGLE_Z:
13507       clutter_actor_set_rotation_angle_internal (actor,
13508                                                  CLUTTER_Z_AXIS,
13509                                                  g_value_get_double (value));
13510       break;
13511
13512     case PROP_CONTENT_BOX:
13513       clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13514       break;
13515
13516     default:
13517       g_object_set_property (obj, pspec->name, value);
13518       break;
13519     }
13520
13521   g_object_thaw_notify (obj);
13522 }
13523
13524 static void
13525 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13526                                const gchar       *property_name,
13527                                const GValue      *final)
13528 {
13529   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13530   ClutterActorMeta *meta = NULL;
13531   gchar *p_name = NULL;
13532
13533   meta = get_meta_from_animation_property (actor,
13534                                            property_name,
13535                                            &p_name);
13536   if (meta != NULL)
13537     g_object_set_property (G_OBJECT (meta), p_name, final);
13538   else
13539     {
13540       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13541       GParamSpec *pspec;
13542
13543       pspec = g_object_class_find_property (obj_class, property_name);
13544
13545       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13546         {
13547           /* XXX - I'm going to the special hell for this */
13548           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13549         }
13550       else
13551         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13552     }
13553
13554   g_free (p_name);
13555 }
13556
13557 static void
13558 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13559 {
13560   iface->find_property = clutter_actor_find_property;
13561   iface->get_initial_state = clutter_actor_get_initial_state;
13562   iface->set_final_state = clutter_actor_set_final_state;
13563 }
13564
13565 /**
13566  * clutter_actor_transform_stage_point:
13567  * @self: A #ClutterActor
13568  * @x: (in): x screen coordinate of the point to unproject
13569  * @y: (in): y screen coordinate of the point to unproject
13570  * @x_out: (out): return location for the unprojected x coordinance
13571  * @y_out: (out): return location for the unprojected y coordinance
13572  *
13573  * This function translates screen coordinates (@x, @y) to
13574  * coordinates relative to the actor. For example, it can be used to translate
13575  * screen events from global screen coordinates into actor-local coordinates.
13576  *
13577  * The conversion can fail, notably if the transform stack results in the
13578  * actor being projected on the screen as a mere line.
13579  *
13580  * The conversion should not be expected to be pixel-perfect due to the
13581  * nature of the operation. In general the error grows when the skewing
13582  * of the actor rectangle on screen increases.
13583  *
13584  * <note><para>This function can be computationally intensive.</para></note>
13585  *
13586  * <note><para>This function only works when the allocation is up-to-date,
13587  * i.e. inside of paint().</para></note>
13588  *
13589  * Return value: %TRUE if conversion was successful.
13590  *
13591  * Since: 0.6
13592  */
13593 gboolean
13594 clutter_actor_transform_stage_point (ClutterActor *self,
13595                                      gfloat        x,
13596                                      gfloat        y,
13597                                      gfloat       *x_out,
13598                                      gfloat       *y_out)
13599 {
13600   ClutterVertex v[4];
13601   float ST[3][3];
13602   float RQ[3][3];
13603   int du, dv, xi, yi;
13604   float px, py;
13605   float xf, yf, wf, det;
13606   ClutterActorPrivate *priv;
13607
13608   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13609
13610   priv = self->priv;
13611
13612   /* This implementation is based on the quad -> quad projection algorithm
13613    * described by Paul Heckbert in:
13614    *
13615    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13616    *
13617    * and the sample implementation at:
13618    *
13619    *   http://www.cs.cmu.edu/~ph/src/texfund/
13620    *
13621    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13622    * quad to rectangle only, which significantly simplifies things; the
13623    * function calls have been unrolled, and most of the math is done in fixed
13624    * point.
13625    */
13626
13627   clutter_actor_get_abs_allocation_vertices (self, v);
13628
13629   /* Keeping these as ints simplifies the multiplication (no significant
13630    * loss of precision here).
13631    */
13632   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13633   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13634
13635   if (!du || !dv)
13636     return FALSE;
13637
13638 #define UX2FP(x)        (x)
13639 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13640
13641   /* First, find mapping from unit uv square to xy quadrilateral; this
13642    * equivalent to the pmap_square_quad() functions in the sample
13643    * implementation, which we can simplify, since our target is always
13644    * a rectangle.
13645    */
13646   px = v[0].x - v[1].x + v[3].x - v[2].x;
13647   py = v[0].y - v[1].y + v[3].y - v[2].y;
13648
13649   if (!px && !py)
13650     {
13651       /* affine transform */
13652       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13653       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13654       RQ[2][0] = UX2FP (v[0].x);
13655       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13656       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13657       RQ[2][1] = UX2FP (v[0].y);
13658       RQ[0][2] = 0;
13659       RQ[1][2] = 0;
13660       RQ[2][2] = 1.0;
13661     }
13662   else
13663     {
13664       /* projective transform */
13665       double dx1, dx2, dy1, dy2, del;
13666
13667       dx1 = UX2FP (v[1].x - v[3].x);
13668       dx2 = UX2FP (v[2].x - v[3].x);
13669       dy1 = UX2FP (v[1].y - v[3].y);
13670       dy2 = UX2FP (v[2].y - v[3].y);
13671
13672       del = DET2FP (dx1, dx2, dy1, dy2);
13673       if (!del)
13674         return FALSE;
13675
13676       /*
13677        * The division here needs to be done in floating point for
13678        * precisions reasons.
13679        */
13680       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13681       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13682       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13683       RQ[2][2] = 1.0;
13684       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13685       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13686       RQ[2][0] = UX2FP (v[0].x);
13687       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13688       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13689       RQ[2][1] = UX2FP (v[0].y);
13690     }
13691
13692   /*
13693    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13694    * square. Since our rectangle is based at 0,0 we only need to scale.
13695    */
13696   RQ[0][0] /= du;
13697   RQ[1][0] /= dv;
13698   RQ[0][1] /= du;
13699   RQ[1][1] /= dv;
13700   RQ[0][2] /= du;
13701   RQ[1][2] /= dv;
13702
13703   /*
13704    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13705    * inverse of that.
13706    */
13707   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13708   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13709   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13710   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13711   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13712   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13713   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13714   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13715   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13716
13717   /*
13718    * Check the resulting matrix is OK.
13719    */
13720   det = (RQ[0][0] * ST[0][0])
13721       + (RQ[0][1] * ST[0][1])
13722       + (RQ[0][2] * ST[0][2]);
13723   if (!det)
13724     return FALSE;
13725
13726   /*
13727    * Now transform our point with the ST matrix; the notional w
13728    * coordinate is 1, hence the last part is simply added.
13729    */
13730   xi = (int) x;
13731   yi = (int) y;
13732
13733   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13734   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13735   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13736
13737   if (x_out)
13738     *x_out = xf / wf;
13739
13740   if (y_out)
13741     *y_out = yf / wf;
13742
13743 #undef UX2FP
13744 #undef DET2FP
13745
13746   return TRUE;
13747 }
13748
13749 /**
13750  * clutter_actor_is_rotated:
13751  * @self: a #ClutterActor
13752  *
13753  * Checks whether any rotation is applied to the actor.
13754  *
13755  * Return value: %TRUE if the actor is rotated.
13756  *
13757  * Since: 0.6
13758  */
13759 gboolean
13760 clutter_actor_is_rotated (ClutterActor *self)
13761 {
13762   const ClutterTransformInfo *info;
13763
13764   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13765
13766   info = _clutter_actor_get_transform_info_or_defaults (self);
13767
13768   if (info->rx_angle || info->ry_angle || info->rz_angle)
13769     return TRUE;
13770
13771   return FALSE;
13772 }
13773
13774 /**
13775  * clutter_actor_is_scaled:
13776  * @self: a #ClutterActor
13777  *
13778  * Checks whether the actor is scaled in either dimension.
13779  *
13780  * Return value: %TRUE if the actor is scaled.
13781  *
13782  * Since: 0.6
13783  */
13784 gboolean
13785 clutter_actor_is_scaled (ClutterActor *self)
13786 {
13787   const ClutterTransformInfo *info;
13788
13789   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13790
13791   info = _clutter_actor_get_transform_info_or_defaults (self);
13792
13793   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13794     return TRUE;
13795
13796   return FALSE;
13797 }
13798
13799 ClutterActor *
13800 _clutter_actor_get_stage_internal (ClutterActor *actor)
13801 {
13802   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13803     actor = actor->priv->parent;
13804
13805   return actor;
13806 }
13807
13808 /**
13809  * clutter_actor_get_stage:
13810  * @actor: a #ClutterActor
13811  *
13812  * Retrieves the #ClutterStage where @actor is contained.
13813  *
13814  * Return value: (transfer none) (type Clutter.Stage): the stage
13815  *   containing the actor, or %NULL
13816  *
13817  * Since: 0.8
13818  */
13819 ClutterActor *
13820 clutter_actor_get_stage (ClutterActor *actor)
13821 {
13822   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13823
13824   return _clutter_actor_get_stage_internal (actor);
13825 }
13826
13827 /**
13828  * clutter_actor_allocate_available_size:
13829  * @self: a #ClutterActor
13830  * @x: the actor's X coordinate
13831  * @y: the actor's Y coordinate
13832  * @available_width: the maximum available width, or -1 to use the
13833  *   actor's natural width
13834  * @available_height: the maximum available height, or -1 to use the
13835  *   actor's natural height
13836  * @flags: flags controlling the allocation
13837  *
13838  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13839  * preferred size, but limiting it to the maximum available width
13840  * and height provided.
13841  *
13842  * This function will do the right thing when dealing with the
13843  * actor's request mode.
13844  *
13845  * The implementation of this function is equivalent to:
13846  *
13847  * |[
13848  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13849  *     {
13850  *       clutter_actor_get_preferred_width (self, available_height,
13851  *                                          &amp;min_width,
13852  *                                          &amp;natural_width);
13853  *       width = CLAMP (natural_width, min_width, available_width);
13854  *
13855  *       clutter_actor_get_preferred_height (self, width,
13856  *                                           &amp;min_height,
13857  *                                           &amp;natural_height);
13858  *       height = CLAMP (natural_height, min_height, available_height);
13859  *     }
13860  *   else
13861  *     {
13862  *       clutter_actor_get_preferred_height (self, available_width,
13863  *                                           &amp;min_height,
13864  *                                           &amp;natural_height);
13865  *       height = CLAMP (natural_height, min_height, available_height);
13866  *
13867  *       clutter_actor_get_preferred_width (self, height,
13868  *                                          &amp;min_width,
13869  *                                          &amp;natural_width);
13870  *       width = CLAMP (natural_width, min_width, available_width);
13871  *     }
13872  *
13873  *   box.x1 = x; box.y1 = y;
13874  *   box.x2 = box.x1 + available_width;
13875  *   box.y2 = box.y1 + available_height;
13876  *   clutter_actor_allocate (self, &amp;box, flags);
13877  * ]|
13878  *
13879  * This function can be used by fluid layout managers to allocate
13880  * an actor's preferred size without making it bigger than the area
13881  * available for the container.
13882  *
13883  * Since: 1.0
13884  */
13885 void
13886 clutter_actor_allocate_available_size (ClutterActor           *self,
13887                                        gfloat                  x,
13888                                        gfloat                  y,
13889                                        gfloat                  available_width,
13890                                        gfloat                  available_height,
13891                                        ClutterAllocationFlags  flags)
13892 {
13893   ClutterActorPrivate *priv;
13894   gfloat width, height;
13895   gfloat min_width, min_height;
13896   gfloat natural_width, natural_height;
13897   ClutterActorBox box;
13898
13899   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13900
13901   priv = self->priv;
13902
13903   width = height = 0.0;
13904
13905   switch (priv->request_mode)
13906     {
13907     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13908       clutter_actor_get_preferred_width (self, available_height,
13909                                          &min_width,
13910                                          &natural_width);
13911       width  = CLAMP (natural_width, min_width, available_width);
13912
13913       clutter_actor_get_preferred_height (self, width,
13914                                           &min_height,
13915                                           &natural_height);
13916       height = CLAMP (natural_height, min_height, available_height);
13917       break;
13918
13919     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13920       clutter_actor_get_preferred_height (self, available_width,
13921                                           &min_height,
13922                                           &natural_height);
13923       height = CLAMP (natural_height, min_height, available_height);
13924
13925       clutter_actor_get_preferred_width (self, height,
13926                                          &min_width,
13927                                          &natural_width);
13928       width  = CLAMP (natural_width, min_width, available_width);
13929       break;
13930     }
13931
13932
13933   box.x1 = x;
13934   box.y1 = y;
13935   box.x2 = box.x1 + width;
13936   box.y2 = box.y1 + height;
13937   clutter_actor_allocate (self, &box, flags);
13938 }
13939
13940 /**
13941  * clutter_actor_allocate_preferred_size:
13942  * @self: a #ClutterActor
13943  * @flags: flags controlling the allocation
13944  *
13945  * Allocates the natural size of @self.
13946  *
13947  * This function is a utility call for #ClutterActor implementations
13948  * that allocates the actor's preferred natural size. It can be used
13949  * by fixed layout managers (like #ClutterGroup or so called
13950  * 'composite actors') inside the ClutterActor::allocate
13951  * implementation to give each child exactly how much space it
13952  * requires.
13953  *
13954  * This function is not meant to be used by applications. It is also
13955  * not meant to be used outside the implementation of the
13956  * ClutterActor::allocate virtual function.
13957  *
13958  * Since: 0.8
13959  */
13960 void
13961 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13962                                        ClutterAllocationFlags  flags)
13963 {
13964   gfloat actor_x, actor_y;
13965   gfloat natural_width, natural_height;
13966   ClutterActorBox actor_box;
13967
13968   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13969
13970   actor_x = clutter_actor_get_x (self);
13971   actor_y = clutter_actor_get_y (self);
13972
13973   clutter_actor_get_preferred_size (self,
13974                                     NULL, NULL,
13975                                     &natural_width,
13976                                     &natural_height);
13977
13978   actor_box.x1 = actor_x;
13979   actor_box.y1 = actor_y;
13980   actor_box.x2 = actor_box.x1 + natural_width;
13981   actor_box.y2 = actor_box.y1 + natural_height;
13982
13983   clutter_actor_allocate (self, &actor_box, flags);
13984 }
13985
13986 /**
13987  * clutter_actor_allocate_align_fill:
13988  * @self: a #ClutterActor
13989  * @box: a #ClutterActorBox, containing the available width and height
13990  * @x_align: the horizontal alignment, between 0 and 1
13991  * @y_align: the vertical alignment, between 0 and 1
13992  * @x_fill: whether the actor should fill horizontally
13993  * @y_fill: whether the actor should fill vertically
13994  * @flags: allocation flags to be passed to clutter_actor_allocate()
13995  *
13996  * Allocates @self by taking into consideration the available allocation
13997  * area; an alignment factor on either axis; and whether the actor should
13998  * fill the allocation on either axis.
13999  *
14000  * The @box should contain the available allocation width and height;
14001  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
14002  * allocation will be offset by their value.
14003  *
14004  * This function takes into consideration the geometry request specified by
14005  * the #ClutterActor:request-mode property, and the text direction.
14006  *
14007  * This function is useful for fluid layout managers, like #ClutterBinLayout
14008  * or #ClutterTableLayout
14009  *
14010  * Since: 1.4
14011  */
14012 void
14013 clutter_actor_allocate_align_fill (ClutterActor           *self,
14014                                    const ClutterActorBox  *box,
14015                                    gdouble                 x_align,
14016                                    gdouble                 y_align,
14017                                    gboolean                x_fill,
14018                                    gboolean                y_fill,
14019                                    ClutterAllocationFlags  flags)
14020 {
14021   ClutterActorPrivate *priv;
14022   ClutterActorBox allocation = { 0, };
14023   gfloat x_offset, y_offset;
14024   gfloat available_width, available_height;
14025   gfloat child_width, child_height;
14026
14027   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14028   g_return_if_fail (box != NULL);
14029   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
14030   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
14031
14032   priv = self->priv;
14033
14034   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
14035   clutter_actor_box_get_size (box, &available_width, &available_height);
14036
14037   if (available_width < 0)
14038     available_width = 0;
14039
14040   if (available_height < 0)
14041     available_height = 0;
14042
14043   if (x_fill)
14044     {
14045       allocation.x1 = x_offset;
14046       allocation.x2 = allocation.x1 + available_width;
14047     }
14048
14049   if (y_fill)
14050     {
14051       allocation.y1 = y_offset;
14052       allocation.y2 = allocation.y1 + available_height;
14053     }
14054
14055   /* if we are filling horizontally and vertically then we're done */
14056   if (x_fill && y_fill)
14057     goto out;
14058
14059   child_width = child_height = 0.0f;
14060
14061   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
14062     {
14063       gfloat min_width, natural_width;
14064       gfloat min_height, natural_height;
14065
14066       clutter_actor_get_preferred_width (self, available_height,
14067                                          &min_width,
14068                                          &natural_width);
14069
14070       child_width = CLAMP (natural_width, min_width, available_width);
14071
14072       if (!y_fill)
14073         {
14074           clutter_actor_get_preferred_height (self, child_width,
14075                                               &min_height,
14076                                               &natural_height);
14077
14078           child_height = CLAMP (natural_height, min_height, available_height);
14079         }
14080     }
14081   else
14082     {
14083       gfloat min_width, natural_width;
14084       gfloat min_height, natural_height;
14085
14086       clutter_actor_get_preferred_height (self, available_width,
14087                                           &min_height,
14088                                           &natural_height);
14089
14090       child_height = CLAMP (natural_height, min_height, available_height);
14091
14092       if (!x_fill)
14093         {
14094           clutter_actor_get_preferred_width (self, child_height,
14095                                              &min_width,
14096                                              &natural_width);
14097
14098           child_width = CLAMP (natural_width, min_width, available_width);
14099         }
14100     }
14101
14102   /* invert the horizontal alignment for RTL languages */
14103   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
14104     x_align = 1.0 - x_align;
14105
14106   if (!x_fill)
14107     {
14108       allocation.x1 = x_offset
14109                     + ((available_width - child_width) * x_align);
14110       allocation.x2 = allocation.x1 + child_width;
14111     }
14112
14113   if (!y_fill)
14114     {
14115       allocation.y1 = y_offset
14116                     + ((available_height - child_height) * y_align);
14117       allocation.y2 = allocation.y1 + child_height;
14118     }
14119
14120 out:
14121   clutter_actor_box_clamp_to_pixel (&allocation);
14122   clutter_actor_allocate (self, &allocation, flags);
14123 }
14124
14125 /**
14126  * clutter_actor_grab_key_focus:
14127  * @self: a #ClutterActor
14128  *
14129  * Sets the key focus of the #ClutterStage including @self
14130  * to this #ClutterActor.
14131  *
14132  * Since: 1.0
14133  */
14134 void
14135 clutter_actor_grab_key_focus (ClutterActor *self)
14136 {
14137   ClutterActor *stage;
14138
14139   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14140
14141   stage = _clutter_actor_get_stage_internal (self);
14142   if (stage != NULL)
14143     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
14144 }
14145
14146 /**
14147  * clutter_actor_get_pango_context:
14148  * @self: a #ClutterActor
14149  *
14150  * Retrieves the #PangoContext for @self. The actor's #PangoContext
14151  * is already configured using the appropriate font map, resolution
14152  * and font options.
14153  *
14154  * Unlike clutter_actor_create_pango_context(), this context is owend
14155  * by the #ClutterActor and it will be updated each time the options
14156  * stored by the #ClutterBackend change.
14157  *
14158  * You can use the returned #PangoContext to create a #PangoLayout
14159  * and render text using cogl_pango_render_layout() to reuse the
14160  * glyphs cache also used by Clutter.
14161  *
14162  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
14163  *   The returned #PangoContext is owned by the actor and should not be
14164  *   unreferenced by the application code
14165  *
14166  * Since: 1.0
14167  */
14168 PangoContext *
14169 clutter_actor_get_pango_context (ClutterActor *self)
14170 {
14171   ClutterActorPrivate *priv;
14172
14173   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14174
14175   priv = self->priv;
14176
14177   if (priv->pango_context != NULL)
14178     return priv->pango_context;
14179
14180   priv->pango_context = _clutter_context_get_pango_context ();
14181   g_object_ref (priv->pango_context);
14182
14183   return priv->pango_context;
14184 }
14185
14186 /**
14187  * clutter_actor_create_pango_context:
14188  * @self: a #ClutterActor
14189  *
14190  * Creates a #PangoContext for the given actor. The #PangoContext
14191  * is already configured using the appropriate font map, resolution
14192  * and font options.
14193  *
14194  * See also clutter_actor_get_pango_context().
14195  *
14196  * Return value: (transfer full): the newly created #PangoContext.
14197  *   Use g_object_unref() on the returned value to deallocate its
14198  *   resources
14199  *
14200  * Since: 1.0
14201  */
14202 PangoContext *
14203 clutter_actor_create_pango_context (ClutterActor *self)
14204 {
14205   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14206
14207   return _clutter_context_create_pango_context ();
14208 }
14209
14210 /**
14211  * clutter_actor_create_pango_layout:
14212  * @self: a #ClutterActor
14213  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14214  *
14215  * Creates a new #PangoLayout from the same #PangoContext used
14216  * by the #ClutterActor. The #PangoLayout is already configured
14217  * with the font map, resolution and font options, and the
14218  * given @text.
14219  *
14220  * If you want to keep around a #PangoLayout created by this
14221  * function you will have to connect to the #ClutterBackend::font-changed
14222  * and #ClutterBackend::resolution-changed signals, and call
14223  * pango_layout_context_changed() in response to them.
14224  *
14225  * Return value: (transfer full): the newly created #PangoLayout.
14226  *   Use g_object_unref() when done
14227  *
14228  * Since: 1.0
14229  */
14230 PangoLayout *
14231 clutter_actor_create_pango_layout (ClutterActor *self,
14232                                    const gchar  *text)
14233 {
14234   PangoContext *context;
14235   PangoLayout *layout;
14236
14237   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14238
14239   context = clutter_actor_get_pango_context (self);
14240   layout = pango_layout_new (context);
14241
14242   if (text)
14243     pango_layout_set_text (layout, text, -1);
14244
14245   return layout;
14246 }
14247
14248 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14249  * ClutterOffscreenEffect.
14250  */
14251 void
14252 _clutter_actor_set_opacity_override (ClutterActor *self,
14253                                      gint          opacity)
14254 {
14255   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14256
14257   self->priv->opacity_override = opacity;
14258 }
14259
14260 gint
14261 _clutter_actor_get_opacity_override (ClutterActor *self)
14262 {
14263   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14264
14265   return self->priv->opacity_override;
14266 }
14267
14268 /* Allows you to disable applying the actors model view transform during
14269  * a paint. Used by ClutterClone. */
14270 void
14271 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14272                                                 gboolean      enable)
14273 {
14274   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14275
14276   self->priv->enable_model_view_transform = enable;
14277 }
14278
14279 void
14280 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14281                                           gboolean      enable)
14282 {
14283   ClutterActorPrivate *priv;
14284
14285   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14286
14287   priv = self->priv;
14288
14289   priv->enable_paint_unmapped = enable;
14290
14291   if (priv->enable_paint_unmapped)
14292     {
14293       /* Make sure that the parents of the widget are realized first;
14294        * otherwise checks in clutter_actor_update_map_state() will
14295        * fail.
14296        */
14297       clutter_actor_realize (self);
14298
14299       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14300     }
14301   else
14302     {
14303       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14304     }
14305 }
14306
14307 static void
14308 clutter_anchor_coord_get_units (ClutterActor      *self,
14309                                 const AnchorCoord *coord,
14310                                 gfloat            *x,
14311                                 gfloat            *y,
14312                                 gfloat            *z)
14313 {
14314   if (coord->is_fractional)
14315     {
14316       gfloat actor_width, actor_height;
14317
14318       clutter_actor_get_size (self, &actor_width, &actor_height);
14319
14320       if (x)
14321         *x = actor_width * coord->v.fraction.x;
14322
14323       if (y)
14324         *y = actor_height * coord->v.fraction.y;
14325
14326       if (z)
14327         *z = 0;
14328     }
14329   else
14330     {
14331       if (x)
14332         *x = coord->v.units.x;
14333
14334       if (y)
14335         *y = coord->v.units.y;
14336
14337       if (z)
14338         *z = coord->v.units.z;
14339     }
14340 }
14341
14342 static void
14343 clutter_anchor_coord_set_units (AnchorCoord *coord,
14344                                 gfloat       x,
14345                                 gfloat       y,
14346                                 gfloat       z)
14347 {
14348   coord->is_fractional = FALSE;
14349   coord->v.units.x = x;
14350   coord->v.units.y = y;
14351   coord->v.units.z = z;
14352 }
14353
14354 static ClutterGravity
14355 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14356 {
14357   if (coord->is_fractional)
14358     {
14359       if (coord->v.fraction.x == 0.0)
14360         {
14361           if (coord->v.fraction.y == 0.0)
14362             return CLUTTER_GRAVITY_NORTH_WEST;
14363           else if (coord->v.fraction.y == 0.5)
14364             return CLUTTER_GRAVITY_WEST;
14365           else if (coord->v.fraction.y == 1.0)
14366             return CLUTTER_GRAVITY_SOUTH_WEST;
14367           else
14368             return CLUTTER_GRAVITY_NONE;
14369         }
14370       else if (coord->v.fraction.x == 0.5)
14371         {
14372           if (coord->v.fraction.y == 0.0)
14373             return CLUTTER_GRAVITY_NORTH;
14374           else if (coord->v.fraction.y == 0.5)
14375             return CLUTTER_GRAVITY_CENTER;
14376           else if (coord->v.fraction.y == 1.0)
14377             return CLUTTER_GRAVITY_SOUTH;
14378           else
14379             return CLUTTER_GRAVITY_NONE;
14380         }
14381       else if (coord->v.fraction.x == 1.0)
14382         {
14383           if (coord->v.fraction.y == 0.0)
14384             return CLUTTER_GRAVITY_NORTH_EAST;
14385           else if (coord->v.fraction.y == 0.5)
14386             return CLUTTER_GRAVITY_EAST;
14387           else if (coord->v.fraction.y == 1.0)
14388             return CLUTTER_GRAVITY_SOUTH_EAST;
14389           else
14390             return CLUTTER_GRAVITY_NONE;
14391         }
14392       else
14393         return CLUTTER_GRAVITY_NONE;
14394     }
14395   else
14396     return CLUTTER_GRAVITY_NONE;
14397 }
14398
14399 static void
14400 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14401                                   ClutterGravity  gravity)
14402 {
14403   switch (gravity)
14404     {
14405     case CLUTTER_GRAVITY_NORTH:
14406       coord->v.fraction.x = 0.5;
14407       coord->v.fraction.y = 0.0;
14408       break;
14409
14410     case CLUTTER_GRAVITY_NORTH_EAST:
14411       coord->v.fraction.x = 1.0;
14412       coord->v.fraction.y = 0.0;
14413       break;
14414
14415     case CLUTTER_GRAVITY_EAST:
14416       coord->v.fraction.x = 1.0;
14417       coord->v.fraction.y = 0.5;
14418       break;
14419
14420     case CLUTTER_GRAVITY_SOUTH_EAST:
14421       coord->v.fraction.x = 1.0;
14422       coord->v.fraction.y = 1.0;
14423       break;
14424
14425     case CLUTTER_GRAVITY_SOUTH:
14426       coord->v.fraction.x = 0.5;
14427       coord->v.fraction.y = 1.0;
14428       break;
14429
14430     case CLUTTER_GRAVITY_SOUTH_WEST:
14431       coord->v.fraction.x = 0.0;
14432       coord->v.fraction.y = 1.0;
14433       break;
14434
14435     case CLUTTER_GRAVITY_WEST:
14436       coord->v.fraction.x = 0.0;
14437       coord->v.fraction.y = 0.5;
14438       break;
14439
14440     case CLUTTER_GRAVITY_NORTH_WEST:
14441       coord->v.fraction.x = 0.0;
14442       coord->v.fraction.y = 0.0;
14443       break;
14444
14445     case CLUTTER_GRAVITY_CENTER:
14446       coord->v.fraction.x = 0.5;
14447       coord->v.fraction.y = 0.5;
14448       break;
14449
14450     default:
14451       coord->v.fraction.x = 0.0;
14452       coord->v.fraction.y = 0.0;
14453       break;
14454     }
14455
14456   coord->is_fractional = TRUE;
14457 }
14458
14459 static gboolean
14460 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14461 {
14462   if (coord->is_fractional)
14463     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14464   else
14465     return (coord->v.units.x == 0.0
14466             && coord->v.units.y == 0.0
14467             && coord->v.units.z == 0.0);
14468 }
14469
14470 /**
14471  * clutter_actor_get_flags:
14472  * @self: a #ClutterActor
14473  *
14474  * Retrieves the flags set on @self
14475  *
14476  * Return value: a bitwise or of #ClutterActorFlags or 0
14477  *
14478  * Since: 1.0
14479  */
14480 ClutterActorFlags
14481 clutter_actor_get_flags (ClutterActor *self)
14482 {
14483   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14484
14485   return self->flags;
14486 }
14487
14488 /**
14489  * clutter_actor_set_flags:
14490  * @self: a #ClutterActor
14491  * @flags: the flags to set
14492  *
14493  * Sets @flags on @self
14494  *
14495  * This function will emit notifications for the changed properties
14496  *
14497  * Since: 1.0
14498  */
14499 void
14500 clutter_actor_set_flags (ClutterActor      *self,
14501                          ClutterActorFlags  flags)
14502 {
14503   ClutterActorFlags old_flags;
14504   GObject *obj;
14505   gboolean was_reactive_set, reactive_set;
14506   gboolean was_realized_set, realized_set;
14507   gboolean was_mapped_set, mapped_set;
14508   gboolean was_visible_set, visible_set;
14509
14510   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14511
14512   if (self->flags == flags)
14513     return;
14514
14515   obj = G_OBJECT (self);
14516   g_object_ref (obj);
14517   g_object_freeze_notify (obj);
14518
14519   old_flags = self->flags;
14520
14521   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14522   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14523   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14524   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14525
14526   self->flags |= flags;
14527
14528   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14529   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14530   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14531   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14532
14533   if (reactive_set != was_reactive_set)
14534     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14535
14536   if (realized_set != was_realized_set)
14537     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14538
14539   if (mapped_set != was_mapped_set)
14540     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14541
14542   if (visible_set != was_visible_set)
14543     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14544
14545   g_object_thaw_notify (obj);
14546   g_object_unref (obj);
14547 }
14548
14549 /**
14550  * clutter_actor_unset_flags:
14551  * @self: a #ClutterActor
14552  * @flags: the flags to unset
14553  *
14554  * Unsets @flags on @self
14555  *
14556  * This function will emit notifications for the changed properties
14557  *
14558  * Since: 1.0
14559  */
14560 void
14561 clutter_actor_unset_flags (ClutterActor      *self,
14562                            ClutterActorFlags  flags)
14563 {
14564   ClutterActorFlags old_flags;
14565   GObject *obj;
14566   gboolean was_reactive_set, reactive_set;
14567   gboolean was_realized_set, realized_set;
14568   gboolean was_mapped_set, mapped_set;
14569   gboolean was_visible_set, visible_set;
14570
14571   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14572
14573   obj = G_OBJECT (self);
14574   g_object_freeze_notify (obj);
14575
14576   old_flags = self->flags;
14577
14578   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14579   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14580   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14581   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14582
14583   self->flags &= ~flags;
14584
14585   if (self->flags == old_flags)
14586     return;
14587
14588   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14589   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14590   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14591   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14592
14593   if (reactive_set != was_reactive_set)
14594     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14595
14596   if (realized_set != was_realized_set)
14597     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14598
14599   if (mapped_set != was_mapped_set)
14600     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14601
14602   if (visible_set != was_visible_set)
14603     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14604
14605   g_object_thaw_notify (obj);
14606 }
14607
14608 /**
14609  * clutter_actor_get_transformation_matrix:
14610  * @self: a #ClutterActor
14611  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14612  *
14613  * Retrieves the transformations applied to @self relative to its
14614  * parent.
14615  *
14616  * Since: 1.0
14617  */
14618 void
14619 clutter_actor_get_transformation_matrix (ClutterActor *self,
14620                                          CoglMatrix   *matrix)
14621 {
14622   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14623
14624   cogl_matrix_init_identity (matrix);
14625
14626   _clutter_actor_apply_modelview_transform (self, matrix);
14627 }
14628
14629 void
14630 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14631                                    gboolean      is_in_clone_paint)
14632 {
14633   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14634   self->priv->in_clone_paint = is_in_clone_paint;
14635 }
14636
14637 /**
14638  * clutter_actor_is_in_clone_paint:
14639  * @self: a #ClutterActor
14640  *
14641  * Checks whether @self is being currently painted by a #ClutterClone
14642  *
14643  * This function is useful only inside the ::paint virtual function
14644  * implementations or within handlers for the #ClutterActor::paint
14645  * signal
14646  *
14647  * This function should not be used by applications
14648  *
14649  * Return value: %TRUE if the #ClutterActor is currently being painted
14650  *   by a #ClutterClone, and %FALSE otherwise
14651  *
14652  * Since: 1.0
14653  */
14654 gboolean
14655 clutter_actor_is_in_clone_paint (ClutterActor *self)
14656 {
14657   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14658
14659   return self->priv->in_clone_paint;
14660 }
14661
14662 static gboolean
14663 set_direction_recursive (ClutterActor *actor,
14664                          gpointer      user_data)
14665 {
14666   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14667
14668   clutter_actor_set_text_direction (actor, text_dir);
14669
14670   return TRUE;
14671 }
14672
14673 /**
14674  * clutter_actor_set_text_direction:
14675  * @self: a #ClutterActor
14676  * @text_dir: the text direction for @self
14677  *
14678  * Sets the #ClutterTextDirection for an actor
14679  *
14680  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14681  *
14682  * If @self implements #ClutterContainer then this function will recurse
14683  * inside all the children of @self (including the internal ones).
14684  *
14685  * Composite actors not implementing #ClutterContainer, or actors requiring
14686  * special handling when the text direction changes, should connect to
14687  * the #GObject::notify signal for the #ClutterActor:text-direction property
14688  *
14689  * Since: 1.2
14690  */
14691 void
14692 clutter_actor_set_text_direction (ClutterActor         *self,
14693                                   ClutterTextDirection  text_dir)
14694 {
14695   ClutterActorPrivate *priv;
14696
14697   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14698   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14699
14700   priv = self->priv;
14701
14702   if (priv->text_direction != text_dir)
14703     {
14704       priv->text_direction = text_dir;
14705
14706       /* we need to emit the notify::text-direction first, so that
14707        * the sub-classes can catch that and do specific handling of
14708        * the text direction; see clutter_text_direction_changed_cb()
14709        * inside clutter-text.c
14710        */
14711       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14712
14713       _clutter_actor_foreach_child (self, set_direction_recursive,
14714                                     GINT_TO_POINTER (text_dir));
14715
14716       clutter_actor_queue_relayout (self);
14717     }
14718 }
14719
14720 void
14721 _clutter_actor_set_has_pointer (ClutterActor *self,
14722                                 gboolean      has_pointer)
14723 {
14724   ClutterActorPrivate *priv = self->priv;
14725
14726   if (priv->has_pointer != has_pointer)
14727     {
14728       priv->has_pointer = has_pointer;
14729
14730       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14731     }
14732 }
14733
14734 /**
14735  * clutter_actor_get_text_direction:
14736  * @self: a #ClutterActor
14737  *
14738  * Retrieves the value set using clutter_actor_set_text_direction()
14739  *
14740  * If no text direction has been previously set, the default text
14741  * direction, as returned by clutter_get_default_text_direction(), will
14742  * be returned instead
14743  *
14744  * Return value: the #ClutterTextDirection for the actor
14745  *
14746  * Since: 1.2
14747  */
14748 ClutterTextDirection
14749 clutter_actor_get_text_direction (ClutterActor *self)
14750 {
14751   ClutterActorPrivate *priv;
14752
14753   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14754                         CLUTTER_TEXT_DIRECTION_LTR);
14755
14756   priv = self->priv;
14757
14758   /* if no direction has been set yet use the default */
14759   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14760     priv->text_direction = clutter_get_default_text_direction ();
14761
14762   return priv->text_direction;
14763 }
14764
14765 /**
14766  * clutter_actor_push_internal:
14767  * @self: a #ClutterActor
14768  *
14769  * Should be used by actors implementing the #ClutterContainer and with
14770  * internal children added through clutter_actor_set_parent(), for instance:
14771  *
14772  * |[
14773  *   static void
14774  *   my_actor_init (MyActor *self)
14775  *   {
14776  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14777  *
14778  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14779  *
14780  *     /&ast; calling clutter_actor_set_parent() now will result in
14781  *      &ast; the internal flag being set on a child of MyActor
14782  *      &ast;/
14783  *
14784  *     /&ast; internal child - a background texture &ast;/
14785  *     self->priv->background_tex = clutter_texture_new ();
14786  *     clutter_actor_set_parent (self->priv->background_tex,
14787  *                               CLUTTER_ACTOR (self));
14788  *
14789  *     /&ast; internal child - a label &ast;/
14790  *     self->priv->label = clutter_text_new ();
14791  *     clutter_actor_set_parent (self->priv->label,
14792  *                               CLUTTER_ACTOR (self));
14793  *
14794  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14795  *
14796  *     /&ast; calling clutter_actor_set_parent() now will not result in
14797  *      &ast; the internal flag being set on a child of MyActor
14798  *      &ast;/
14799  *   }
14800  * ]|
14801  *
14802  * This function will be used by Clutter to toggle an "internal child"
14803  * flag whenever clutter_actor_set_parent() is called; internal children
14804  * are handled differently by Clutter, specifically when destroying their
14805  * parent.
14806  *
14807  * Call clutter_actor_pop_internal() when you finished adding internal
14808  * children.
14809  *
14810  * Nested calls to clutter_actor_push_internal() are allowed, but each
14811  * one must by followed by a clutter_actor_pop_internal() call.
14812  *
14813  * Since: 1.2
14814  *
14815  * Deprecated: 1.10: All children of an actor are accessible through
14816  *   the #ClutterActor API, and #ClutterActor implements the
14817  *   #ClutterContainer interface, so this function is only useful
14818  *   for legacy containers overriding the default implementation.
14819  */
14820 void
14821 clutter_actor_push_internal (ClutterActor *self)
14822 {
14823   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14824
14825   self->priv->internal_child += 1;
14826 }
14827
14828 /**
14829  * clutter_actor_pop_internal:
14830  * @self: a #ClutterActor
14831  *
14832  * Disables the effects of clutter_actor_push_internal().
14833  *
14834  * Since: 1.2
14835  *
14836  * Deprecated: 1.10: All children of an actor are accessible through
14837  *   the #ClutterActor API. This function is only useful for legacy
14838  *   containers overriding the default implementation of the
14839  *   #ClutterContainer interface.
14840  */
14841 void
14842 clutter_actor_pop_internal (ClutterActor *self)
14843 {
14844   ClutterActorPrivate *priv;
14845
14846   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14847
14848   priv = self->priv;
14849
14850   if (priv->internal_child == 0)
14851     {
14852       g_warning ("Mismatched %s: you need to call "
14853                  "clutter_actor_push_composite() at least once before "
14854                  "calling this function", G_STRFUNC);
14855       return;
14856     }
14857
14858   priv->internal_child -= 1;
14859 }
14860
14861 /**
14862  * clutter_actor_has_pointer:
14863  * @self: a #ClutterActor
14864  *
14865  * Checks whether an actor contains the pointer of a
14866  * #ClutterInputDevice
14867  *
14868  * Return value: %TRUE if the actor contains the pointer, and
14869  *   %FALSE otherwise
14870  *
14871  * Since: 1.2
14872  */
14873 gboolean
14874 clutter_actor_has_pointer (ClutterActor *self)
14875 {
14876   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14877
14878   return self->priv->has_pointer;
14879 }
14880
14881 /* XXX: This is a workaround for not being able to break the ABI of
14882  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14883  * clutter_actor_queue_clipped_redraw() for details.
14884  */
14885 ClutterPaintVolume *
14886 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14887 {
14888   return g_object_get_data (G_OBJECT (self),
14889                             "-clutter-actor-queue-redraw-clip");
14890 }
14891
14892 void
14893 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14894                                       ClutterPaintVolume *clip)
14895 {
14896   g_object_set_data (G_OBJECT (self),
14897                      "-clutter-actor-queue-redraw-clip",
14898                      clip);
14899 }
14900
14901 /**
14902  * clutter_actor_has_allocation:
14903  * @self: a #ClutterActor
14904  *
14905  * Checks if the actor has an up-to-date allocation assigned to
14906  * it. This means that the actor should have an allocation: it's
14907  * visible and has a parent. It also means that there is no
14908  * outstanding relayout request in progress for the actor or its
14909  * children (There might be other outstanding layout requests in
14910  * progress that will cause the actor to get a new allocation
14911  * when the stage is laid out, however).
14912  *
14913  * If this function returns %FALSE, then the actor will normally
14914  * be allocated before it is next drawn on the screen.
14915  *
14916  * Return value: %TRUE if the actor has an up-to-date allocation
14917  *
14918  * Since: 1.4
14919  */
14920 gboolean
14921 clutter_actor_has_allocation (ClutterActor *self)
14922 {
14923   ClutterActorPrivate *priv;
14924
14925   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14926
14927   priv = self->priv;
14928
14929   return priv->parent != NULL &&
14930          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14931          !priv->needs_allocation;
14932 }
14933
14934 /**
14935  * clutter_actor_add_action:
14936  * @self: a #ClutterActor
14937  * @action: a #ClutterAction
14938  *
14939  * Adds @action to the list of actions applied to @self
14940  *
14941  * A #ClutterAction can only belong to one actor at a time
14942  *
14943  * The #ClutterActor will hold a reference on @action until either
14944  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14945  * is called
14946  *
14947  * Since: 1.4
14948  */
14949 void
14950 clutter_actor_add_action (ClutterActor  *self,
14951                           ClutterAction *action)
14952 {
14953   ClutterActorPrivate *priv;
14954
14955   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14956   g_return_if_fail (CLUTTER_IS_ACTION (action));
14957
14958   priv = self->priv;
14959
14960   if (priv->actions == NULL)
14961     {
14962       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14963       priv->actions->actor = self;
14964     }
14965
14966   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14967
14968   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14969 }
14970
14971 /**
14972  * clutter_actor_add_action_with_name:
14973  * @self: a #ClutterActor
14974  * @name: the name to set on the action
14975  * @action: a #ClutterAction
14976  *
14977  * A convenience function for setting the name of a #ClutterAction
14978  * while adding it to the list of actions applied to @self
14979  *
14980  * This function is the logical equivalent of:
14981  *
14982  * |[
14983  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14984  *   clutter_actor_add_action (self, action);
14985  * ]|
14986  *
14987  * Since: 1.4
14988  */
14989 void
14990 clutter_actor_add_action_with_name (ClutterActor  *self,
14991                                     const gchar   *name,
14992                                     ClutterAction *action)
14993 {
14994   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14995   g_return_if_fail (name != NULL);
14996   g_return_if_fail (CLUTTER_IS_ACTION (action));
14997
14998   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14999   clutter_actor_add_action (self, action);
15000 }
15001
15002 /**
15003  * clutter_actor_remove_action:
15004  * @self: a #ClutterActor
15005  * @action: a #ClutterAction
15006  *
15007  * Removes @action from the list of actions applied to @self
15008  *
15009  * The reference held by @self on the #ClutterAction will be released
15010  *
15011  * Since: 1.4
15012  */
15013 void
15014 clutter_actor_remove_action (ClutterActor  *self,
15015                              ClutterAction *action)
15016 {
15017   ClutterActorPrivate *priv;
15018
15019   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15020   g_return_if_fail (CLUTTER_IS_ACTION (action));
15021
15022   priv = self->priv;
15023
15024   if (priv->actions == NULL)
15025     return;
15026
15027   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
15028
15029   if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
15030     g_clear_object (&priv->actions);
15031
15032   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15033 }
15034
15035 /**
15036  * clutter_actor_remove_action_by_name:
15037  * @self: a #ClutterActor
15038  * @name: the name of the action to remove
15039  *
15040  * Removes the #ClutterAction with the given name from the list
15041  * of actions applied to @self
15042  *
15043  * Since: 1.4
15044  */
15045 void
15046 clutter_actor_remove_action_by_name (ClutterActor *self,
15047                                      const gchar  *name)
15048 {
15049   ClutterActorPrivate *priv;
15050   ClutterActorMeta *meta;
15051
15052   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15053   g_return_if_fail (name != NULL);
15054
15055   priv = self->priv;
15056
15057   if (priv->actions == NULL)
15058     return;
15059
15060   meta = _clutter_meta_group_get_meta (priv->actions, name);
15061   if (meta == NULL)
15062     return;
15063
15064   _clutter_meta_group_remove_meta (priv->actions, meta);
15065
15066   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15067 }
15068
15069 /**
15070  * clutter_actor_get_actions:
15071  * @self: a #ClutterActor
15072  *
15073  * Retrieves the list of actions applied to @self
15074  *
15075  * Return value: (transfer container) (element-type Clutter.Action): a copy
15076  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
15077  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15078  *   allocated by the returned #GList
15079  *
15080  * Since: 1.4
15081  */
15082 GList *
15083 clutter_actor_get_actions (ClutterActor *self)
15084 {
15085   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15086
15087   if (self->priv->actions == NULL)
15088     return NULL;
15089
15090   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
15091 }
15092
15093 /**
15094  * clutter_actor_get_action:
15095  * @self: a #ClutterActor
15096  * @name: the name of the action to retrieve
15097  *
15098  * Retrieves the #ClutterAction with the given name in the list
15099  * of actions applied to @self
15100  *
15101  * Return value: (transfer none): a #ClutterAction for the given
15102  *   name, or %NULL. The returned #ClutterAction is owned by the
15103  *   actor and it should not be unreferenced directly
15104  *
15105  * Since: 1.4
15106  */
15107 ClutterAction *
15108 clutter_actor_get_action (ClutterActor *self,
15109                           const gchar  *name)
15110 {
15111   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15112   g_return_val_if_fail (name != NULL, NULL);
15113
15114   if (self->priv->actions == NULL)
15115     return NULL;
15116
15117   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
15118 }
15119
15120 /**
15121  * clutter_actor_clear_actions:
15122  * @self: a #ClutterActor
15123  *
15124  * Clears the list of actions applied to @self
15125  *
15126  * Since: 1.4
15127  */
15128 void
15129 clutter_actor_clear_actions (ClutterActor *self)
15130 {
15131   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15132
15133   if (self->priv->actions == NULL)
15134     return;
15135
15136   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
15137 }
15138
15139 /**
15140  * clutter_actor_add_constraint:
15141  * @self: a #ClutterActor
15142  * @constraint: a #ClutterConstraint
15143  *
15144  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
15145  * to @self
15146  *
15147  * The #ClutterActor will hold a reference on the @constraint until
15148  * either clutter_actor_remove_constraint() or
15149  * clutter_actor_clear_constraints() is called.
15150  *
15151  * Since: 1.4
15152  */
15153 void
15154 clutter_actor_add_constraint (ClutterActor      *self,
15155                               ClutterConstraint *constraint)
15156 {
15157   ClutterActorPrivate *priv;
15158
15159   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15160   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15161
15162   priv = self->priv;
15163
15164   if (priv->constraints == NULL)
15165     {
15166       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15167       priv->constraints->actor = self;
15168     }
15169
15170   _clutter_meta_group_add_meta (priv->constraints,
15171                                 CLUTTER_ACTOR_META (constraint));
15172   clutter_actor_queue_relayout (self);
15173
15174   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15175 }
15176
15177 /**
15178  * clutter_actor_add_constraint_with_name:
15179  * @self: a #ClutterActor
15180  * @name: the name to set on the constraint
15181  * @constraint: a #ClutterConstraint
15182  *
15183  * A convenience function for setting the name of a #ClutterConstraint
15184  * while adding it to the list of constraints applied to @self
15185  *
15186  * This function is the logical equivalent of:
15187  *
15188  * |[
15189  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15190  *   clutter_actor_add_constraint (self, constraint);
15191  * ]|
15192  *
15193  * Since: 1.4
15194  */
15195 void
15196 clutter_actor_add_constraint_with_name (ClutterActor      *self,
15197                                         const gchar       *name,
15198                                         ClutterConstraint *constraint)
15199 {
15200   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15201   g_return_if_fail (name != NULL);
15202   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15203
15204   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15205   clutter_actor_add_constraint (self, constraint);
15206 }
15207
15208 /**
15209  * clutter_actor_remove_constraint:
15210  * @self: a #ClutterActor
15211  * @constraint: a #ClutterConstraint
15212  *
15213  * Removes @constraint from the list of constraints applied to @self
15214  *
15215  * The reference held by @self on the #ClutterConstraint will be released
15216  *
15217  * Since: 1.4
15218  */
15219 void
15220 clutter_actor_remove_constraint (ClutterActor      *self,
15221                                  ClutterConstraint *constraint)
15222 {
15223   ClutterActorPrivate *priv;
15224
15225   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15226   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15227
15228   priv = self->priv;
15229
15230   if (priv->constraints == NULL)
15231     return;
15232
15233   _clutter_meta_group_remove_meta (priv->constraints,
15234                                    CLUTTER_ACTOR_META (constraint));
15235
15236   if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15237     g_clear_object (&priv->constraints);
15238
15239   clutter_actor_queue_relayout (self);
15240
15241   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15242 }
15243
15244 /**
15245  * clutter_actor_remove_constraint_by_name:
15246  * @self: a #ClutterActor
15247  * @name: the name of the constraint to remove
15248  *
15249  * Removes the #ClutterConstraint with the given name from the list
15250  * of constraints applied to @self
15251  *
15252  * Since: 1.4
15253  */
15254 void
15255 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15256                                          const gchar  *name)
15257 {
15258   ClutterActorPrivate *priv;
15259   ClutterActorMeta *meta;
15260
15261   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15262   g_return_if_fail (name != NULL);
15263
15264   priv = self->priv;
15265
15266   if (priv->constraints == NULL)
15267     return;
15268
15269   meta = _clutter_meta_group_get_meta (priv->constraints, name);
15270   if (meta == NULL)
15271     return;
15272
15273   _clutter_meta_group_remove_meta (priv->constraints, meta);
15274   clutter_actor_queue_relayout (self);
15275 }
15276
15277 /**
15278  * clutter_actor_get_constraints:
15279  * @self: a #ClutterActor
15280  *
15281  * Retrieves the list of constraints applied to @self
15282  *
15283  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15284  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15285  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15286  *   allocated by the returned #GList
15287  *
15288  * Since: 1.4
15289  */
15290 GList *
15291 clutter_actor_get_constraints (ClutterActor *self)
15292 {
15293   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15294
15295   if (self->priv->constraints == NULL)
15296     return NULL;
15297
15298   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15299 }
15300
15301 /**
15302  * clutter_actor_get_constraint:
15303  * @self: a #ClutterActor
15304  * @name: the name of the constraint to retrieve
15305  *
15306  * Retrieves the #ClutterConstraint with the given name in the list
15307  * of constraints applied to @self
15308  *
15309  * Return value: (transfer none): a #ClutterConstraint for the given
15310  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15311  *   actor and it should not be unreferenced directly
15312  *
15313  * Since: 1.4
15314  */
15315 ClutterConstraint *
15316 clutter_actor_get_constraint (ClutterActor *self,
15317                               const gchar  *name)
15318 {
15319   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15320   g_return_val_if_fail (name != NULL, NULL);
15321
15322   if (self->priv->constraints == NULL)
15323     return NULL;
15324
15325   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15326 }
15327
15328 /**
15329  * clutter_actor_clear_constraints:
15330  * @self: a #ClutterActor
15331  *
15332  * Clears the list of constraints applied to @self
15333  *
15334  * Since: 1.4
15335  */
15336 void
15337 clutter_actor_clear_constraints (ClutterActor *self)
15338 {
15339   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15340
15341   if (self->priv->constraints == NULL)
15342     return;
15343
15344   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15345
15346   clutter_actor_queue_relayout (self);
15347 }
15348
15349 /**
15350  * clutter_actor_set_clip_to_allocation:
15351  * @self: a #ClutterActor
15352  * @clip_set: %TRUE to apply a clip tracking the allocation
15353  *
15354  * Sets whether @self should be clipped to the same size as its
15355  * allocation
15356  *
15357  * Since: 1.4
15358  */
15359 void
15360 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15361                                       gboolean      clip_set)
15362 {
15363   ClutterActorPrivate *priv;
15364
15365   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15366
15367   clip_set = !!clip_set;
15368
15369   priv = self->priv;
15370
15371   if (priv->clip_to_allocation != clip_set)
15372     {
15373       priv->clip_to_allocation = clip_set;
15374
15375       clutter_actor_queue_redraw (self);
15376
15377       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15378     }
15379 }
15380
15381 /**
15382  * clutter_actor_get_clip_to_allocation:
15383  * @self: a #ClutterActor
15384  *
15385  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15386  *
15387  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15388  *
15389  * Since: 1.4
15390  */
15391 gboolean
15392 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15393 {
15394   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15395
15396   return self->priv->clip_to_allocation;
15397 }
15398
15399 /**
15400  * clutter_actor_add_effect:
15401  * @self: a #ClutterActor
15402  * @effect: a #ClutterEffect
15403  *
15404  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15405  *
15406  * The #ClutterActor will hold a reference on the @effect until either
15407  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15408  * called.
15409  *
15410  * Since: 1.4
15411  */
15412 void
15413 clutter_actor_add_effect (ClutterActor  *self,
15414                           ClutterEffect *effect)
15415 {
15416   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15417   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15418
15419   _clutter_actor_add_effect_internal (self, effect);
15420
15421   clutter_actor_queue_redraw (self);
15422
15423   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15424 }
15425
15426 /**
15427  * clutter_actor_add_effect_with_name:
15428  * @self: a #ClutterActor
15429  * @name: the name to set on the effect
15430  * @effect: a #ClutterEffect
15431  *
15432  * A convenience function for setting the name of a #ClutterEffect
15433  * while adding it to the list of effectss applied to @self
15434  *
15435  * This function is the logical equivalent of:
15436  *
15437  * |[
15438  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15439  *   clutter_actor_add_effect (self, effect);
15440  * ]|
15441  *
15442  * Since: 1.4
15443  */
15444 void
15445 clutter_actor_add_effect_with_name (ClutterActor  *self,
15446                                     const gchar   *name,
15447                                     ClutterEffect *effect)
15448 {
15449   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15450   g_return_if_fail (name != NULL);
15451   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15452
15453   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15454   clutter_actor_add_effect (self, effect);
15455 }
15456
15457 /**
15458  * clutter_actor_remove_effect:
15459  * @self: a #ClutterActor
15460  * @effect: a #ClutterEffect
15461  *
15462  * Removes @effect from the list of effects applied to @self
15463  *
15464  * The reference held by @self on the #ClutterEffect will be released
15465  *
15466  * Since: 1.4
15467  */
15468 void
15469 clutter_actor_remove_effect (ClutterActor  *self,
15470                              ClutterEffect *effect)
15471 {
15472   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15473   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15474
15475   _clutter_actor_remove_effect_internal (self, effect);
15476
15477   clutter_actor_queue_redraw (self);
15478
15479   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15480 }
15481
15482 /**
15483  * clutter_actor_remove_effect_by_name:
15484  * @self: a #ClutterActor
15485  * @name: the name of the effect to remove
15486  *
15487  * Removes the #ClutterEffect with the given name from the list
15488  * of effects applied to @self
15489  *
15490  * Since: 1.4
15491  */
15492 void
15493 clutter_actor_remove_effect_by_name (ClutterActor *self,
15494                                      const gchar  *name)
15495 {
15496   ClutterActorPrivate *priv;
15497   ClutterActorMeta *meta;
15498
15499   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15500   g_return_if_fail (name != NULL);
15501
15502   priv = self->priv;
15503
15504   if (priv->effects == NULL)
15505     return;
15506
15507   meta = _clutter_meta_group_get_meta (priv->effects, name);
15508   if (meta == NULL)
15509     return;
15510
15511   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15512 }
15513
15514 /**
15515  * clutter_actor_get_effects:
15516  * @self: a #ClutterActor
15517  *
15518  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15519  *
15520  * Return value: (transfer container) (element-type Clutter.Effect): a list
15521  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15522  *   list are owned by Clutter and they should not be freed. You should
15523  *   free the returned list using g_list_free() when done
15524  *
15525  * Since: 1.4
15526  */
15527 GList *
15528 clutter_actor_get_effects (ClutterActor *self)
15529 {
15530   ClutterActorPrivate *priv;
15531
15532   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15533
15534   priv = self->priv;
15535
15536   if (priv->effects == NULL)
15537     return NULL;
15538
15539   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15540 }
15541
15542 /**
15543  * clutter_actor_get_effect:
15544  * @self: a #ClutterActor
15545  * @name: the name of the effect to retrieve
15546  *
15547  * Retrieves the #ClutterEffect with the given name in the list
15548  * of effects applied to @self
15549  *
15550  * Return value: (transfer none): a #ClutterEffect for the given
15551  *   name, or %NULL. The returned #ClutterEffect is owned by the
15552  *   actor and it should not be unreferenced directly
15553  *
15554  * Since: 1.4
15555  */
15556 ClutterEffect *
15557 clutter_actor_get_effect (ClutterActor *self,
15558                           const gchar  *name)
15559 {
15560   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15561   g_return_val_if_fail (name != NULL, NULL);
15562
15563   if (self->priv->effects == NULL)
15564     return NULL;
15565
15566   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15567 }
15568
15569 /**
15570  * clutter_actor_clear_effects:
15571  * @self: a #ClutterActor
15572  *
15573  * Clears the list of effects applied to @self
15574  *
15575  * Since: 1.4
15576  */
15577 void
15578 clutter_actor_clear_effects (ClutterActor *self)
15579 {
15580   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15581
15582   if (self->priv->effects == NULL)
15583     return;
15584
15585   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15586
15587   clutter_actor_queue_redraw (self);
15588 }
15589
15590 /**
15591  * clutter_actor_has_key_focus:
15592  * @self: a #ClutterActor
15593  *
15594  * Checks whether @self is the #ClutterActor that has key focus
15595  *
15596  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15597  *
15598  * Since: 1.4
15599  */
15600 gboolean
15601 clutter_actor_has_key_focus (ClutterActor *self)
15602 {
15603   ClutterActor *stage;
15604
15605   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15606
15607   stage = _clutter_actor_get_stage_internal (self);
15608   if (stage == NULL)
15609     return FALSE;
15610
15611   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15612 }
15613
15614 static gboolean
15615 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15616                                       ClutterPaintVolume *pv)
15617 {
15618   ClutterActorPrivate *priv = self->priv;
15619
15620   /* Actors are only expected to report a valid paint volume
15621    * while they have a valid allocation. */
15622   if (G_UNLIKELY (priv->needs_allocation))
15623     {
15624       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15625                     "Actor needs allocation",
15626                     _clutter_actor_get_debug_name (self));
15627       return FALSE;
15628     }
15629
15630   /* Check if there are any handlers connected to the paint
15631    * signal. If there are then all bets are off for what the paint
15632    * volume for this actor might possibly be!
15633    *
15634    * XXX: It's expected that this is going to end up being quite a
15635    * costly check to have to do here, but we haven't come up with
15636    * another solution that can reliably catch paint signal handlers at
15637    * the right time to either avoid artefacts due to invalid stage
15638    * clipping or due to incorrect culling.
15639    *
15640    * Previously we checked in clutter_actor_paint(), but at that time
15641    * we may already be using a stage clip that could be derived from
15642    * an invalid paint-volume. We used to try and handle that by
15643    * queuing a follow up, unclipped, redraw but still the previous
15644    * checking wasn't enough to catch invalid volumes involved in
15645    * culling (considering that containers may derive their volume from
15646    * children that haven't yet been painted)
15647    *
15648    * Longer term, improved solutions could be:
15649    * - Disallow painting in the paint signal, only allow using it
15650    *   for tracking when paints happen. We can add another API that
15651    *   allows monkey patching the paint of arbitrary actors but in a
15652    *   more controlled way and that also supports modifying the
15653    *   paint-volume.
15654    * - If we could be notified somehow when signal handlers are
15655    *   connected we wouldn't have to poll for handlers like this.
15656    */
15657   if (g_signal_has_handler_pending (self,
15658                                     actor_signals[PAINT],
15659                                     0,
15660                                     TRUE))
15661     {
15662       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15663                     "Actor has \"paint\" signal handlers",
15664                     _clutter_actor_get_debug_name (self));
15665       return FALSE;
15666     }
15667
15668   _clutter_paint_volume_init_static (pv, self);
15669
15670   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15671     {
15672       clutter_paint_volume_free (pv);
15673       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15674                     "Actor failed to report a volume",
15675                     _clutter_actor_get_debug_name (self));
15676       return FALSE;
15677     }
15678
15679   /* since effects can modify the paint volume, we allow them to actually
15680    * do this by making get_paint_volume() "context sensitive"
15681    */
15682   if (priv->effects != NULL)
15683     {
15684       if (priv->current_effect != NULL)
15685         {
15686           const GList *effects, *l;
15687
15688           /* if we are being called from within the paint sequence of
15689            * an actor, get the paint volume up to the current effect
15690            */
15691           effects = _clutter_meta_group_peek_metas (priv->effects);
15692           for (l = effects;
15693                l != NULL || (l != NULL && l->data != priv->current_effect);
15694                l = l->next)
15695             {
15696               if (!_clutter_effect_get_paint_volume (l->data, pv))
15697                 {
15698                   clutter_paint_volume_free (pv);
15699                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15700                                 "Effect (%s) failed to report a volume",
15701                                 _clutter_actor_get_debug_name (self),
15702                                 _clutter_actor_meta_get_debug_name (l->data));
15703                   return FALSE;
15704                 }
15705             }
15706         }
15707       else
15708         {
15709           const GList *effects, *l;
15710
15711           /* otherwise, get the cumulative volume */
15712           effects = _clutter_meta_group_peek_metas (priv->effects);
15713           for (l = effects; l != NULL; l = l->next)
15714             if (!_clutter_effect_get_paint_volume (l->data, pv))
15715               {
15716                 clutter_paint_volume_free (pv);
15717                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15718                               "Effect (%s) failed to report a volume",
15719                               _clutter_actor_get_debug_name (self),
15720                               _clutter_actor_meta_get_debug_name (l->data));
15721                 return FALSE;
15722               }
15723         }
15724     }
15725
15726   return TRUE;
15727 }
15728
15729 /* The public clutter_actor_get_paint_volume API returns a const
15730  * pointer since we return a pointer directly to the cached
15731  * PaintVolume associated with the actor and don't want the user to
15732  * inadvertently modify it, but for internal uses we sometimes need
15733  * access to the same PaintVolume but need to apply some book-keeping
15734  * modifications to it so we don't want a const pointer.
15735  */
15736 static ClutterPaintVolume *
15737 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15738 {
15739   ClutterActorPrivate *priv;
15740
15741   priv = self->priv;
15742
15743   if (priv->paint_volume_valid)
15744     clutter_paint_volume_free (&priv->paint_volume);
15745
15746   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15747     {
15748       priv->paint_volume_valid = TRUE;
15749       return &priv->paint_volume;
15750     }
15751   else
15752     {
15753       priv->paint_volume_valid = FALSE;
15754       return NULL;
15755     }
15756 }
15757
15758 /**
15759  * clutter_actor_get_paint_volume:
15760  * @self: a #ClutterActor
15761  *
15762  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15763  * when a paint volume can't be determined.
15764  *
15765  * The paint volume is defined as the 3D space occupied by an actor
15766  * when being painted.
15767  *
15768  * This function will call the <function>get_paint_volume()</function>
15769  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15770  * should not usually care about overriding the default implementation,
15771  * unless they are, for instance: painting outside their allocation, or
15772  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15773  * 3D depth).
15774  *
15775  * <note>2D actors overriding <function>get_paint_volume()</function>
15776  * ensure their volume has a depth of 0. (This will be true so long as
15777  * you don't call clutter_paint_volume_set_depth().)</note>
15778  *
15779  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15780  *   or %NULL if no volume could be determined. The returned pointer
15781  *   is not guaranteed to be valid across multiple frames; if you want
15782  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15783  *
15784  * Since: 1.6
15785  */
15786 const ClutterPaintVolume *
15787 clutter_actor_get_paint_volume (ClutterActor *self)
15788 {
15789   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15790
15791   return _clutter_actor_get_paint_volume_mutable (self);
15792 }
15793
15794 /**
15795  * clutter_actor_get_transformed_paint_volume:
15796  * @self: a #ClutterActor
15797  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15798  *    (or %NULL for the stage)
15799  *
15800  * Retrieves the 3D paint volume of an actor like
15801  * clutter_actor_get_paint_volume() does (Please refer to the
15802  * documentation of clutter_actor_get_paint_volume() for more
15803  * details.) and it additionally transforms the paint volume into the
15804  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15805  * is passed for @relative_to_ancestor)
15806  *
15807  * This can be used by containers that base their paint volume on
15808  * the volume of their children. Such containers can query the
15809  * transformed paint volume of all of its children and union them
15810  * together using clutter_paint_volume_union().
15811  *
15812  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15813  *   or %NULL if no volume could be determined. The returned pointer is
15814  *   not guaranteed to be valid across multiple frames; if you wish to
15815  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15816  *
15817  * Since: 1.6
15818  */
15819 const ClutterPaintVolume *
15820 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15821                                             ClutterActor *relative_to_ancestor)
15822 {
15823   const ClutterPaintVolume *volume;
15824   ClutterActor *stage;
15825   ClutterPaintVolume *transformed_volume;
15826
15827   stage = _clutter_actor_get_stage_internal (self);
15828   if (G_UNLIKELY (stage == NULL))
15829     return NULL;
15830
15831   if (relative_to_ancestor == NULL)
15832     relative_to_ancestor = stage;
15833
15834   volume = clutter_actor_get_paint_volume (self);
15835   if (volume == NULL)
15836     return NULL;
15837
15838   transformed_volume =
15839     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15840
15841   _clutter_paint_volume_copy_static (volume, transformed_volume);
15842
15843   _clutter_paint_volume_transform_relative (transformed_volume,
15844                                             relative_to_ancestor);
15845
15846   return transformed_volume;
15847 }
15848
15849 /**
15850  * clutter_actor_get_paint_box:
15851  * @self: a #ClutterActor
15852  * @box: (out): return location for a #ClutterActorBox
15853  *
15854  * Retrieves the paint volume of the passed #ClutterActor, and
15855  * transforms it into a 2D bounding box in stage coordinates.
15856  *
15857  * This function is useful to determine the on screen area occupied by
15858  * the actor. The box is only an approximation and may often be
15859  * considerably larger due to the optimizations used to calculate the
15860  * box. The box is never smaller though, so it can reliably be used
15861  * for culling.
15862  *
15863  * There are times when a 2D paint box can't be determined, e.g.
15864  * because the actor isn't yet parented under a stage or because
15865  * the actor is unable to determine a paint volume.
15866  *
15867  * Return value: %TRUE if a 2D paint box could be determined, else
15868  * %FALSE.
15869  *
15870  * Since: 1.6
15871  */
15872 gboolean
15873 clutter_actor_get_paint_box (ClutterActor    *self,
15874                              ClutterActorBox *box)
15875 {
15876   ClutterActor *stage;
15877   ClutterPaintVolume *pv;
15878
15879   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15880   g_return_val_if_fail (box != NULL, FALSE);
15881
15882   stage = _clutter_actor_get_stage_internal (self);
15883   if (G_UNLIKELY (!stage))
15884     return FALSE;
15885
15886   pv = _clutter_actor_get_paint_volume_mutable (self);
15887   if (G_UNLIKELY (!pv))
15888     return FALSE;
15889
15890   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15891
15892   return TRUE;
15893 }
15894
15895 /**
15896  * clutter_actor_has_overlaps:
15897  * @self: A #ClutterActor
15898  *
15899  * Asks the actor's implementation whether it may contain overlapping
15900  * primitives.
15901  *
15902  * For example; Clutter may use this to determine whether the painting
15903  * should be redirected to an offscreen buffer to correctly implement
15904  * the opacity property.
15905  *
15906  * Custom actors can override the default response by implementing the
15907  * #ClutterActor <function>has_overlaps</function> virtual function. See
15908  * clutter_actor_set_offscreen_redirect() for more information.
15909  *
15910  * Return value: %TRUE if the actor may have overlapping primitives, and
15911  *   %FALSE otherwise
15912  *
15913  * Since: 1.8
15914  */
15915 gboolean
15916 clutter_actor_has_overlaps (ClutterActor *self)
15917 {
15918   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15919
15920   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15921 }
15922
15923 /**
15924  * clutter_actor_has_effects:
15925  * @self: A #ClutterActor
15926  *
15927  * Returns whether the actor has any effects applied.
15928  *
15929  * Return value: %TRUE if the actor has any effects,
15930  *   %FALSE otherwise
15931  *
15932  * Since: 1.10
15933  */
15934 gboolean
15935 clutter_actor_has_effects (ClutterActor *self)
15936 {
15937   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15938
15939   if (self->priv->effects == NULL)
15940     return FALSE;
15941
15942   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15943 }
15944
15945 /**
15946  * clutter_actor_has_constraints:
15947  * @self: A #ClutterActor
15948  *
15949  * Returns whether the actor has any constraints applied.
15950  *
15951  * Return value: %TRUE if the actor has any constraints,
15952  *   %FALSE otherwise
15953  *
15954  * Since: 1.10
15955  */
15956 gboolean
15957 clutter_actor_has_constraints (ClutterActor *self)
15958 {
15959   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15960
15961   return self->priv->constraints != NULL;
15962 }
15963
15964 /**
15965  * clutter_actor_has_actions:
15966  * @self: A #ClutterActor
15967  *
15968  * Returns whether the actor has any actions applied.
15969  *
15970  * Return value: %TRUE if the actor has any actions,
15971  *   %FALSE otherwise
15972  *
15973  * Since: 1.10
15974  */
15975 gboolean
15976 clutter_actor_has_actions (ClutterActor *self)
15977 {
15978   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15979
15980   return self->priv->actions != NULL;
15981 }
15982
15983 /**
15984  * clutter_actor_get_n_children:
15985  * @self: a #ClutterActor
15986  *
15987  * Retrieves the number of children of @self.
15988  *
15989  * Return value: the number of children of an actor
15990  *
15991  * Since: 1.10
15992  */
15993 gint
15994 clutter_actor_get_n_children (ClutterActor *self)
15995 {
15996   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15997
15998   return self->priv->n_children;
15999 }
16000
16001 /**
16002  * clutter_actor_get_child_at_index:
16003  * @self: a #ClutterActor
16004  * @index_: the position in the list of children
16005  *
16006  * Retrieves the actor at the given @index_ inside the list of
16007  * children of @self.
16008  *
16009  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16010  *
16011  * Since: 1.10
16012  */
16013 ClutterActor *
16014 clutter_actor_get_child_at_index (ClutterActor *self,
16015                                   gint          index_)
16016 {
16017   ClutterActor *iter;
16018   int i;
16019
16020   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16021   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
16022
16023   for (iter = self->priv->first_child, i = 0;
16024        iter != NULL && i < index_;
16025        iter = iter->priv->next_sibling, i += 1)
16026     ;
16027
16028   return iter;
16029 }
16030
16031 /*< private >
16032  * _clutter_actor_foreach_child:
16033  * @actor: The actor whos children you want to iterate
16034  * @callback: The function to call for each child
16035  * @user_data: Private data to pass to @callback
16036  *
16037  * Calls a given @callback once for each child of the specified @actor and
16038  * passing the @user_data pointer each time.
16039  *
16040  * Return value: returns %TRUE if all children were iterated, else
16041  *    %FALSE if a callback broke out of iteration early.
16042  */
16043 gboolean
16044 _clutter_actor_foreach_child (ClutterActor           *self,
16045                               ClutterForeachCallback  callback,
16046                               gpointer                user_data)
16047 {
16048   ClutterActor *iter;
16049   gboolean cont;
16050
16051   if (self->priv->first_child == NULL)
16052     return TRUE;
16053
16054   cont = TRUE;
16055   iter = self->priv->first_child;
16056
16057   /* we use this form so that it's safe to change the children
16058    * list while iterating it
16059    */
16060   while (cont && iter != NULL)
16061     {
16062       ClutterActor *next = iter->priv->next_sibling;
16063
16064       cont = callback (iter, user_data);
16065
16066       iter = next;
16067     }
16068
16069   return cont;
16070 }
16071
16072 #if 0
16073 /* For debugging purposes this gives us a simple way to print out
16074  * the scenegraph e.g in gdb using:
16075  * [|
16076  *   _clutter_actor_traverse (stage,
16077  *                            0,
16078  *                            clutter_debug_print_actor_cb,
16079  *                            NULL,
16080  *                            NULL);
16081  * |]
16082  */
16083 static ClutterActorTraverseVisitFlags
16084 clutter_debug_print_actor_cb (ClutterActor *actor,
16085                               int depth,
16086                               void *user_data)
16087 {
16088   g_print ("%*s%s:%p\n",
16089            depth * 2, "",
16090            _clutter_actor_get_debug_name (actor),
16091            actor);
16092
16093   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16094 }
16095 #endif
16096
16097 static void
16098 _clutter_actor_traverse_breadth (ClutterActor           *actor,
16099                                  ClutterTraverseCallback callback,
16100                                  gpointer                user_data)
16101 {
16102   GQueue *queue = g_queue_new ();
16103   ClutterActor dummy;
16104   int current_depth = 0;
16105
16106   g_queue_push_tail (queue, actor);
16107   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
16108
16109   while ((actor = g_queue_pop_head (queue)))
16110     {
16111       ClutterActorTraverseVisitFlags flags;
16112
16113       if (actor == &dummy)
16114         {
16115           current_depth++;
16116           g_queue_push_tail (queue, &dummy);
16117           continue;
16118         }
16119
16120       flags = callback (actor, current_depth, user_data);
16121       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16122         break;
16123       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16124         {
16125           ClutterActor *iter;
16126
16127           for (iter = actor->priv->first_child;
16128                iter != NULL;
16129                iter = iter->priv->next_sibling)
16130             {
16131               g_queue_push_tail (queue, iter);
16132             }
16133         }
16134     }
16135
16136   g_queue_free (queue);
16137 }
16138
16139 static ClutterActorTraverseVisitFlags
16140 _clutter_actor_traverse_depth (ClutterActor           *actor,
16141                                ClutterTraverseCallback before_children_callback,
16142                                ClutterTraverseCallback after_children_callback,
16143                                int                     current_depth,
16144                                gpointer                user_data)
16145 {
16146   ClutterActorTraverseVisitFlags flags;
16147
16148   flags = before_children_callback (actor, current_depth, user_data);
16149   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16150     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16151
16152   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16153     {
16154       ClutterActor *iter;
16155
16156       for (iter = actor->priv->first_child;
16157            iter != NULL;
16158            iter = iter->priv->next_sibling)
16159         {
16160           flags = _clutter_actor_traverse_depth (iter,
16161                                                  before_children_callback,
16162                                                  after_children_callback,
16163                                                  current_depth + 1,
16164                                                  user_data);
16165
16166           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16167             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16168         }
16169     }
16170
16171   if (after_children_callback)
16172     return after_children_callback (actor, current_depth, user_data);
16173   else
16174     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16175 }
16176
16177 /* _clutter_actor_traverse:
16178  * @actor: The actor to start traversing the graph from
16179  * @flags: These flags may affect how the traversal is done
16180  * @before_children_callback: A function to call before visiting the
16181  *   children of the current actor.
16182  * @after_children_callback: A function to call after visiting the
16183  *   children of the current actor. (Ignored if
16184  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
16185  * @user_data: The private data to pass to the callbacks
16186  *
16187  * Traverses the scenegraph starting at the specified @actor and
16188  * descending through all its children and its children's children.
16189  * For each actor traversed @before_children_callback and
16190  * @after_children_callback are called with the specified
16191  * @user_data, before and after visiting that actor's children.
16192  *
16193  * The callbacks can return flags that affect the ongoing traversal
16194  * such as by skipping over an actors children or bailing out of
16195  * any further traversing.
16196  */
16197 void
16198 _clutter_actor_traverse (ClutterActor              *actor,
16199                          ClutterActorTraverseFlags  flags,
16200                          ClutterTraverseCallback    before_children_callback,
16201                          ClutterTraverseCallback    after_children_callback,
16202                          gpointer                   user_data)
16203 {
16204   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
16205     _clutter_actor_traverse_breadth (actor,
16206                                      before_children_callback,
16207                                      user_data);
16208   else /* DEPTH_FIRST */
16209     _clutter_actor_traverse_depth (actor,
16210                                    before_children_callback,
16211                                    after_children_callback,
16212                                    0, /* start depth */
16213                                    user_data);
16214 }
16215
16216 static void
16217 on_layout_manager_changed (ClutterLayoutManager *manager,
16218                            ClutterActor         *self)
16219 {
16220   clutter_actor_queue_relayout (self);
16221 }
16222
16223 /**
16224  * clutter_actor_set_layout_manager:
16225  * @self: a #ClutterActor
16226  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
16227  *
16228  * Sets the #ClutterLayoutManager delegate object that will be used to
16229  * lay out the children of @self.
16230  *
16231  * The #ClutterActor will take a reference on the passed @manager which
16232  * will be released either when the layout manager is removed, or when
16233  * the actor is destroyed.
16234  *
16235  * Since: 1.10
16236  */
16237 void
16238 clutter_actor_set_layout_manager (ClutterActor         *self,
16239                                   ClutterLayoutManager *manager)
16240 {
16241   ClutterActorPrivate *priv;
16242
16243   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16244   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16245
16246   priv = self->priv;
16247
16248   if (priv->layout_manager != NULL)
16249     {
16250       g_signal_handlers_disconnect_by_func (priv->layout_manager,
16251                                             G_CALLBACK (on_layout_manager_changed),
16252                                             self);
16253       clutter_layout_manager_set_container (priv->layout_manager, NULL);
16254       g_clear_object (&priv->layout_manager);
16255     }
16256
16257   priv->layout_manager = manager;
16258
16259   if (priv->layout_manager != NULL)
16260     {
16261       g_object_ref_sink (priv->layout_manager);
16262       clutter_layout_manager_set_container (priv->layout_manager,
16263                                             CLUTTER_CONTAINER (self));
16264       g_signal_connect (priv->layout_manager, "layout-changed",
16265                         G_CALLBACK (on_layout_manager_changed),
16266                         self);
16267     }
16268
16269   clutter_actor_queue_relayout (self);
16270
16271   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16272 }
16273
16274 /**
16275  * clutter_actor_get_layout_manager:
16276  * @self: a #ClutterActor
16277  *
16278  * Retrieves the #ClutterLayoutManager used by @self.
16279  *
16280  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16281  *   or %NULL
16282  *
16283  * Since: 1.10
16284  */
16285 ClutterLayoutManager *
16286 clutter_actor_get_layout_manager (ClutterActor *self)
16287 {
16288   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16289
16290   return self->priv->layout_manager;
16291 }
16292
16293 static const ClutterLayoutInfo default_layout_info = {
16294   CLUTTER_POINT_INIT_ZERO,      /* fixed-pos */
16295   { 0, 0, 0, 0 },               /* margin */
16296   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
16297   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
16298   FALSE, FALSE,                 /* expand */
16299   CLUTTER_SIZE_INIT_ZERO,       /* minimum */
16300   CLUTTER_SIZE_INIT_ZERO,       /* natural */
16301 };
16302
16303 static void
16304 layout_info_free (gpointer data)
16305 {
16306   if (G_LIKELY (data != NULL))
16307     g_slice_free (ClutterLayoutInfo, data);
16308 }
16309
16310 /*< private >
16311  * _clutter_actor_get_layout_info:
16312  * @self: a #ClutterActor
16313  *
16314  * Retrieves a pointer to the ClutterLayoutInfo structure.
16315  *
16316  * If the actor does not have a ClutterLayoutInfo associated to it, one
16317  * will be created and initialized to the default values.
16318  *
16319  * This function should be used for setters.
16320  *
16321  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16322  * instead.
16323  *
16324  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16325  */
16326 ClutterLayoutInfo *
16327 _clutter_actor_get_layout_info (ClutterActor *self)
16328 {
16329   ClutterLayoutInfo *retval;
16330
16331   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16332   if (retval == NULL)
16333     {
16334       retval = g_slice_new (ClutterLayoutInfo);
16335
16336       *retval = default_layout_info;
16337
16338       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16339                                retval,
16340                                layout_info_free);
16341     }
16342
16343   return retval;
16344 }
16345
16346 /*< private >
16347  * _clutter_actor_get_layout_info_or_defaults:
16348  * @self: a #ClutterActor
16349  *
16350  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16351  *
16352  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16353  * then the default structure will be returned.
16354  *
16355  * This function should only be used for getters.
16356  *
16357  * Return value: a const pointer to the ClutterLayoutInfo structure
16358  */
16359 const ClutterLayoutInfo *
16360 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16361 {
16362   const ClutterLayoutInfo *info;
16363
16364   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16365   if (info == NULL)
16366     return &default_layout_info;
16367
16368   return info;
16369 }
16370
16371 /**
16372  * clutter_actor_set_x_align:
16373  * @self: a #ClutterActor
16374  * @x_align: the horizontal alignment policy
16375  *
16376  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16377  * actor received extra horizontal space.
16378  *
16379  * See also the #ClutterActor:x-align property.
16380  *
16381  * Since: 1.10
16382  */
16383 void
16384 clutter_actor_set_x_align (ClutterActor      *self,
16385                            ClutterActorAlign  x_align)
16386 {
16387   ClutterLayoutInfo *info;
16388
16389   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16390
16391   info = _clutter_actor_get_layout_info (self);
16392
16393   if (info->x_align != x_align)
16394     {
16395       info->x_align = x_align;
16396
16397       clutter_actor_queue_relayout (self);
16398
16399       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16400     }
16401 }
16402
16403 /**
16404  * clutter_actor_get_x_align:
16405  * @self: a #ClutterActor
16406  *
16407  * Retrieves the horizontal alignment policy set using
16408  * clutter_actor_set_x_align().
16409  *
16410  * Return value: the horizontal alignment policy.
16411  *
16412  * Since: 1.10
16413  */
16414 ClutterActorAlign
16415 clutter_actor_get_x_align (ClutterActor *self)
16416 {
16417   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16418
16419   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16420 }
16421
16422 /**
16423  * clutter_actor_set_y_align:
16424  * @self: a #ClutterActor
16425  * @y_align: the vertical alignment policy
16426  *
16427  * Sets the vertical alignment policy of a #ClutterActor, in case the
16428  * actor received extra vertical space.
16429  *
16430  * See also the #ClutterActor:y-align property.
16431  *
16432  * Since: 1.10
16433  */
16434 void
16435 clutter_actor_set_y_align (ClutterActor      *self,
16436                            ClutterActorAlign  y_align)
16437 {
16438   ClutterLayoutInfo *info;
16439
16440   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16441
16442   info = _clutter_actor_get_layout_info (self);
16443
16444   if (info->y_align != y_align)
16445     {
16446       info->y_align = y_align;
16447
16448       clutter_actor_queue_relayout (self);
16449
16450       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16451     }
16452 }
16453
16454 /**
16455  * clutter_actor_get_y_align:
16456  * @self: a #ClutterActor
16457  *
16458  * Retrieves the vertical alignment policy set using
16459  * clutter_actor_set_y_align().
16460  *
16461  * Return value: the vertical alignment policy.
16462  *
16463  * Since: 1.10
16464  */
16465 ClutterActorAlign
16466 clutter_actor_get_y_align (ClutterActor *self)
16467 {
16468   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16469
16470   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16471 }
16472
16473 /**
16474  * clutter_actor_set_margin:
16475  * @self: a #ClutterActor
16476  * @margin: a #ClutterMargin
16477  *
16478  * Sets all the components of the margin of a #ClutterActor.
16479  *
16480  * Since: 1.10
16481  */
16482 void
16483 clutter_actor_set_margin (ClutterActor        *self,
16484                           const ClutterMargin *margin)
16485 {
16486   ClutterLayoutInfo *info;
16487   gboolean changed;
16488   GObject *obj;
16489
16490   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16491   g_return_if_fail (margin != NULL);
16492
16493   obj = G_OBJECT (self);
16494   changed = FALSE;
16495
16496   g_object_freeze_notify (obj);
16497
16498   info = _clutter_actor_get_layout_info (self);
16499
16500   if (info->margin.top != margin->top)
16501     {
16502       info->margin.top = margin->top;
16503       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16504       changed = TRUE;
16505     }
16506
16507   if (info->margin.right != margin->right)
16508     {
16509       info->margin.right = margin->right;
16510       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16511       changed = TRUE;
16512     }
16513
16514   if (info->margin.bottom != margin->bottom)
16515     {
16516       info->margin.bottom = margin->bottom;
16517       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16518       changed = TRUE;
16519     }
16520
16521   if (info->margin.left != margin->left)
16522     {
16523       info->margin.left = margin->left;
16524       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16525       changed = TRUE;
16526     }
16527
16528   if (changed)
16529     clutter_actor_queue_relayout (self);
16530
16531   g_object_thaw_notify (obj);
16532 }
16533
16534 /**
16535  * clutter_actor_get_margin:
16536  * @self: a #ClutterActor
16537  * @margin: (out caller-allocates): return location for a #ClutterMargin
16538  *
16539  * Retrieves all the components of the margin of a #ClutterActor.
16540  *
16541  * Since: 1.10
16542  */
16543 void
16544 clutter_actor_get_margin (ClutterActor  *self,
16545                           ClutterMargin *margin)
16546 {
16547   const ClutterLayoutInfo *info;
16548
16549   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16550   g_return_if_fail (margin != NULL);
16551
16552   info = _clutter_actor_get_layout_info_or_defaults (self);
16553
16554   *margin = info->margin;
16555 }
16556
16557 /**
16558  * clutter_actor_set_margin_top:
16559  * @self: a #ClutterActor
16560  * @margin: the top margin
16561  *
16562  * Sets the margin from the top of a #ClutterActor.
16563  *
16564  * Since: 1.10
16565  */
16566 void
16567 clutter_actor_set_margin_top (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.top == margin)
16578     return;
16579
16580   info->margin.top = margin;
16581
16582   clutter_actor_queue_relayout (self);
16583
16584   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16585 }
16586
16587 /**
16588  * clutter_actor_get_margin_top:
16589  * @self: a #ClutterActor
16590  *
16591  * Retrieves the top margin of a #ClutterActor.
16592  *
16593  * Return value: the top margin
16594  *
16595  * Since: 1.10
16596  */
16597 gfloat
16598 clutter_actor_get_margin_top (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.top;
16603 }
16604
16605 /**
16606  * clutter_actor_set_margin_bottom:
16607  * @self: a #ClutterActor
16608  * @margin: the bottom margin
16609  *
16610  * Sets the margin from the bottom of a #ClutterActor.
16611  *
16612  * Since: 1.10
16613  */
16614 void
16615 clutter_actor_set_margin_bottom (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.bottom == margin)
16626     return;
16627
16628   info->margin.bottom = margin;
16629
16630   clutter_actor_queue_relayout (self);
16631
16632   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16633 }
16634
16635 /**
16636  * clutter_actor_get_margin_bottom:
16637  * @self: a #ClutterActor
16638  *
16639  * Retrieves the bottom margin of a #ClutterActor.
16640  *
16641  * Return value: the bottom margin
16642  *
16643  * Since: 1.10
16644  */
16645 gfloat
16646 clutter_actor_get_margin_bottom (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.bottom;
16651 }
16652
16653 /**
16654  * clutter_actor_set_margin_left:
16655  * @self: a #ClutterActor
16656  * @margin: the left margin
16657  *
16658  * Sets the margin from the left of a #ClutterActor.
16659  *
16660  * Since: 1.10
16661  */
16662 void
16663 clutter_actor_set_margin_left (ClutterActor *self,
16664                                gfloat        margin)
16665 {
16666   ClutterLayoutInfo *info;
16667
16668   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16669   g_return_if_fail (margin >= 0.f);
16670
16671   info = _clutter_actor_get_layout_info (self);
16672
16673   if (info->margin.left == margin)
16674     return;
16675
16676   info->margin.left = margin;
16677
16678   clutter_actor_queue_relayout (self);
16679
16680   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16681 }
16682
16683 /**
16684  * clutter_actor_get_margin_left:
16685  * @self: a #ClutterActor
16686  *
16687  * Retrieves the left margin of a #ClutterActor.
16688  *
16689  * Return value: the left margin
16690  *
16691  * Since: 1.10
16692  */
16693 gfloat
16694 clutter_actor_get_margin_left (ClutterActor *self)
16695 {
16696   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16697
16698   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16699 }
16700
16701 /**
16702  * clutter_actor_set_margin_right:
16703  * @self: a #ClutterActor
16704  * @margin: the right margin
16705  *
16706  * Sets the margin from the right of a #ClutterActor.
16707  *
16708  * Since: 1.10
16709  */
16710 void
16711 clutter_actor_set_margin_right (ClutterActor *self,
16712                                 gfloat        margin)
16713 {
16714   ClutterLayoutInfo *info;
16715
16716   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16717   g_return_if_fail (margin >= 0.f);
16718
16719   info = _clutter_actor_get_layout_info (self);
16720
16721   if (info->margin.right == margin)
16722     return;
16723
16724   info->margin.right = margin;
16725
16726   clutter_actor_queue_relayout (self);
16727
16728   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16729 }
16730
16731 /**
16732  * clutter_actor_get_margin_right:
16733  * @self: a #ClutterActor
16734  *
16735  * Retrieves the right margin of a #ClutterActor.
16736  *
16737  * Return value: the right margin
16738  *
16739  * Since: 1.10
16740  */
16741 gfloat
16742 clutter_actor_get_margin_right (ClutterActor *self)
16743 {
16744   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16745
16746   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16747 }
16748
16749 static inline void
16750 clutter_actor_set_background_color_internal (ClutterActor *self,
16751                                              const ClutterColor *color)
16752 {
16753   ClutterActorPrivate *priv = self->priv;
16754   GObject *obj;
16755
16756   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16757     return;
16758
16759   obj = G_OBJECT (self);
16760
16761   priv->bg_color = *color;
16762   priv->bg_color_set = TRUE;
16763
16764   clutter_actor_queue_redraw (self);
16765
16766   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16767   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16768 }
16769
16770 /**
16771  * clutter_actor_set_background_color:
16772  * @self: a #ClutterActor
16773  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16774  *  set color
16775  *
16776  * Sets the background color of a #ClutterActor.
16777  *
16778  * The background color will be used to cover the whole allocation of the
16779  * actor. The default background color of an actor is transparent.
16780  *
16781  * To check whether an actor has a background color, you can use the
16782  * #ClutterActor:background-color-set actor property.
16783  *
16784  * The #ClutterActor:background-color property is animatable.
16785  *
16786  * Since: 1.10
16787  */
16788 void
16789 clutter_actor_set_background_color (ClutterActor       *self,
16790                                     const ClutterColor *color)
16791 {
16792   ClutterActorPrivate *priv;
16793   GObject *obj;
16794   GParamSpec *bg_color_pspec;
16795
16796   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16797
16798   obj = G_OBJECT (self);
16799
16800   priv = self->priv;
16801
16802   if (color == NULL)
16803     {
16804       priv->bg_color_set = FALSE;
16805       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16806       clutter_actor_queue_redraw (self);
16807       return;
16808     }
16809
16810   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16811   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16812     {
16813       _clutter_actor_create_transition (self, bg_color_pspec,
16814                                         &priv->bg_color,
16815                                         color);
16816     }
16817   else
16818     _clutter_actor_update_transition (self, bg_color_pspec, color);
16819
16820   clutter_actor_queue_redraw (self);
16821 }
16822
16823 /**
16824  * clutter_actor_get_background_color:
16825  * @self: a #ClutterActor
16826  * @color: (out caller-allocates): return location for a #ClutterColor
16827  *
16828  * Retrieves the color set using clutter_actor_set_background_color().
16829  *
16830  * Since: 1.10
16831  */
16832 void
16833 clutter_actor_get_background_color (ClutterActor *self,
16834                                     ClutterColor *color)
16835 {
16836   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16837   g_return_if_fail (color != NULL);
16838
16839   *color = self->priv->bg_color;
16840 }
16841
16842 /**
16843  * clutter_actor_get_previous_sibling:
16844  * @self: a #ClutterActor
16845  *
16846  * Retrieves the sibling of @self that comes before it in the list
16847  * of children of @self's parent.
16848  *
16849  * The returned pointer is only valid until the scene graph changes; it
16850  * is not safe to modify the list of children of @self while iterating
16851  * it.
16852  *
16853  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16854  *
16855  * Since: 1.10
16856  */
16857 ClutterActor *
16858 clutter_actor_get_previous_sibling (ClutterActor *self)
16859 {
16860   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16861
16862   return self->priv->prev_sibling;
16863 }
16864
16865 /**
16866  * clutter_actor_get_next_sibling:
16867  * @self: a #ClutterActor
16868  *
16869  * Retrieves the sibling of @self that comes after it in the list
16870  * of children of @self's parent.
16871  *
16872  * The returned pointer is only valid until the scene graph changes; it
16873  * is not safe to modify the list of children of @self while iterating
16874  * it.
16875  *
16876  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16877  *
16878  * Since: 1.10
16879  */
16880 ClutterActor *
16881 clutter_actor_get_next_sibling (ClutterActor *self)
16882 {
16883   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16884
16885   return self->priv->next_sibling;
16886 }
16887
16888 /**
16889  * clutter_actor_get_first_child:
16890  * @self: a #ClutterActor
16891  *
16892  * Retrieves the first child of @self.
16893  *
16894  * The returned pointer is only valid until the scene graph changes; it
16895  * is not safe to modify the list of children of @self while iterating
16896  * it.
16897  *
16898  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16899  *
16900  * Since: 1.10
16901  */
16902 ClutterActor *
16903 clutter_actor_get_first_child (ClutterActor *self)
16904 {
16905   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16906
16907   return self->priv->first_child;
16908 }
16909
16910 /**
16911  * clutter_actor_get_last_child:
16912  * @self: a #ClutterActor
16913  *
16914  * Retrieves the last child of @self.
16915  *
16916  * The returned pointer is only valid until the scene graph changes; it
16917  * is not safe to modify the list of children of @self while iterating
16918  * it.
16919  *
16920  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16921  *
16922  * Since: 1.10
16923  */
16924 ClutterActor *
16925 clutter_actor_get_last_child (ClutterActor *self)
16926 {
16927   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16928
16929   return self->priv->last_child;
16930 }
16931
16932 /* easy way to have properly named fields instead of the dummy ones
16933  * we use in the public structure
16934  */
16935 typedef struct _RealActorIter
16936 {
16937   ClutterActor *root;           /* dummy1 */
16938   ClutterActor *current;        /* dummy2 */
16939   gpointer padding_1;           /* dummy3 */
16940   gint age;                     /* dummy4 */
16941   gpointer padding_2;           /* dummy5 */
16942 } RealActorIter;
16943
16944 /**
16945  * clutter_actor_iter_init:
16946  * @iter: a #ClutterActorIter
16947  * @root: a #ClutterActor
16948  *
16949  * Initializes a #ClutterActorIter, which can then be used to iterate
16950  * efficiently over a section of the scene graph, and associates it
16951  * with @root.
16952  *
16953  * Modifying the scene graph section that contains @root will invalidate
16954  * the iterator.
16955  *
16956  * |[
16957  *   ClutterActorIter iter;
16958  *   ClutterActor *child;
16959  *
16960  *   clutter_actor_iter_init (&iter, container);
16961  *   while (clutter_actor_iter_next (&iter, &child))
16962  *     {
16963  *       /&ast; do something with child &ast;/
16964  *     }
16965  * ]|
16966  *
16967  * Since: 1.10
16968  */
16969 void
16970 clutter_actor_iter_init (ClutterActorIter *iter,
16971                          ClutterActor     *root)
16972 {
16973   RealActorIter *ri = (RealActorIter *) iter;
16974
16975   g_return_if_fail (iter != NULL);
16976   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16977
16978   ri->root = root;
16979   ri->current = NULL;
16980   ri->age = root->priv->age;
16981 }
16982
16983 /**
16984  * clutter_actor_iter_next:
16985  * @iter: a #ClutterActorIter
16986  * @child: (out): return location for a #ClutterActor
16987  *
16988  * Advances the @iter and retrieves the next child of the root #ClutterActor
16989  * that was used to initialize the #ClutterActorIterator.
16990  *
16991  * If the iterator can advance, this function returns %TRUE and sets the
16992  * @child argument.
16993  *
16994  * If the iterator cannot advance, this function returns %FALSE, and
16995  * the contents of @child are undefined.
16996  *
16997  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16998  *
16999  * Since: 1.10
17000  */
17001 gboolean
17002 clutter_actor_iter_next (ClutterActorIter  *iter,
17003                          ClutterActor     **child)
17004 {
17005   RealActorIter *ri = (RealActorIter *) iter;
17006
17007   g_return_val_if_fail (iter != NULL, FALSE);
17008   g_return_val_if_fail (ri->root != NULL, FALSE);
17009 #ifndef G_DISABLE_ASSERT
17010   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17011 #endif
17012
17013   if (ri->current == NULL)
17014     ri->current = ri->root->priv->first_child;
17015   else
17016     ri->current = ri->current->priv->next_sibling;
17017
17018   if (child != NULL)
17019     *child = ri->current;
17020
17021   return ri->current != NULL;
17022 }
17023
17024 /**
17025  * clutter_actor_iter_prev:
17026  * @iter: a #ClutterActorIter
17027  * @child: (out): return location for a #ClutterActor
17028  *
17029  * Advances the @iter and retrieves the previous child of the root
17030  * #ClutterActor that was used to initialize the #ClutterActorIterator.
17031  *
17032  * If the iterator can advance, this function returns %TRUE and sets the
17033  * @child argument.
17034  *
17035  * If the iterator cannot advance, this function returns %FALSE, and
17036  * the contents of @child are undefined.
17037  *
17038  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17039  *
17040  * Since: 1.10
17041  */
17042 gboolean
17043 clutter_actor_iter_prev (ClutterActorIter  *iter,
17044                          ClutterActor     **child)
17045 {
17046   RealActorIter *ri = (RealActorIter *) iter;
17047
17048   g_return_val_if_fail (iter != NULL, FALSE);
17049   g_return_val_if_fail (ri->root != NULL, FALSE);
17050 #ifndef G_DISABLE_ASSERT
17051   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17052 #endif
17053
17054   if (ri->current == NULL)
17055     ri->current = ri->root->priv->last_child;
17056   else
17057     ri->current = ri->current->priv->prev_sibling;
17058
17059   if (child != NULL)
17060     *child = ri->current;
17061
17062   return ri->current != NULL;
17063 }
17064
17065 /**
17066  * clutter_actor_iter_remove:
17067  * @iter: a #ClutterActorIter
17068  *
17069  * Safely removes the #ClutterActor currently pointer to by the iterator
17070  * from its parent.
17071  *
17072  * This function can only be called after clutter_actor_iter_next() or
17073  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17074  * than once for the same actor.
17075  *
17076  * This function will call clutter_actor_remove_child() internally.
17077  *
17078  * Since: 1.10
17079  */
17080 void
17081 clutter_actor_iter_remove (ClutterActorIter *iter)
17082 {
17083   RealActorIter *ri = (RealActorIter *) iter;
17084   ClutterActor *cur;
17085
17086   g_return_if_fail (iter != NULL);
17087   g_return_if_fail (ri->root != NULL);
17088 #ifndef G_DISABLE_ASSERT
17089   g_return_if_fail (ri->age == ri->root->priv->age);
17090 #endif
17091   g_return_if_fail (ri->current != NULL);
17092
17093   cur = ri->current;
17094
17095   if (cur != NULL)
17096     {
17097       ri->current = cur->priv->prev_sibling;
17098
17099       clutter_actor_remove_child_internal (ri->root, cur,
17100                                            REMOVE_CHILD_DEFAULT_FLAGS);
17101
17102       ri->age += 1;
17103     }
17104 }
17105
17106 /**
17107  * clutter_actor_iter_destroy:
17108  * @iter: a #ClutterActorIter
17109  *
17110  * Safely destroys the #ClutterActor currently pointer to by the iterator
17111  * from its parent.
17112  *
17113  * This function can only be called after clutter_actor_iter_next() or
17114  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17115  * than once for the same actor.
17116  *
17117  * This function will call clutter_actor_destroy() internally.
17118  *
17119  * Since: 1.10
17120  */
17121 void
17122 clutter_actor_iter_destroy (ClutterActorIter *iter)
17123 {
17124   RealActorIter *ri = (RealActorIter *) iter;
17125   ClutterActor *cur;
17126
17127   g_return_if_fail (iter != NULL);
17128   g_return_if_fail (ri->root != NULL);
17129 #ifndef G_DISABLE_ASSERT
17130   g_return_if_fail (ri->age == ri->root->priv->age);
17131 #endif
17132   g_return_if_fail (ri->current != NULL);
17133
17134   cur = ri->current;
17135
17136   if (cur != NULL)
17137     {
17138       ri->current = cur->priv->prev_sibling;
17139
17140       clutter_actor_destroy (cur);
17141
17142       ri->age += 1;
17143     }
17144 }
17145
17146 static const ClutterAnimationInfo default_animation_info = {
17147   NULL,         /* transitions */
17148   NULL,         /* states */
17149   NULL,         /* cur_state */
17150 };
17151
17152 static void
17153 clutter_animation_info_free (gpointer data)
17154 {
17155   if (data != NULL)
17156     {
17157       ClutterAnimationInfo *info = data;
17158
17159       if (info->transitions != NULL)
17160         g_hash_table_unref (info->transitions);
17161
17162       if (info->states != NULL)
17163         g_array_unref (info->states);
17164
17165       g_slice_free (ClutterAnimationInfo, info);
17166     }
17167 }
17168
17169 const ClutterAnimationInfo *
17170 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17171 {
17172   const ClutterAnimationInfo *res;
17173   GObject *obj = G_OBJECT (self);
17174
17175   res = g_object_get_qdata (obj, quark_actor_animation_info);
17176   if (res != NULL)
17177     return res;
17178
17179   return &default_animation_info;
17180 }
17181
17182 ClutterAnimationInfo *
17183 _clutter_actor_get_animation_info (ClutterActor *self)
17184 {
17185   GObject *obj = G_OBJECT (self);
17186   ClutterAnimationInfo *res;
17187
17188   res = g_object_get_qdata (obj, quark_actor_animation_info);
17189   if (res == NULL)
17190     {
17191       res = g_slice_new (ClutterAnimationInfo);
17192
17193       *res = default_animation_info;
17194
17195       g_object_set_qdata_full (obj, quark_actor_animation_info,
17196                                res,
17197                                clutter_animation_info_free);
17198     }
17199
17200   return res;
17201 }
17202
17203 ClutterTransition *
17204 _clutter_actor_get_transition (ClutterActor *actor,
17205                                GParamSpec   *pspec)
17206 {
17207   const ClutterAnimationInfo *info;
17208
17209   info = _clutter_actor_get_animation_info_or_defaults (actor);
17210
17211   if (info->transitions == NULL)
17212     return NULL;
17213
17214   return g_hash_table_lookup (info->transitions, pspec->name);
17215 }
17216
17217 typedef struct _TransitionClosure
17218 {
17219   ClutterActor *actor;
17220   ClutterTransition *transition;
17221   gchar *name;
17222   gulong completed_id;
17223 } TransitionClosure;
17224
17225 static void
17226 transition_closure_free (gpointer data)
17227 {
17228   if (G_LIKELY (data != NULL))
17229     {
17230       TransitionClosure *clos = data;
17231       ClutterTimeline *timeline;
17232
17233       timeline = CLUTTER_TIMELINE (clos->transition);
17234
17235       if (clutter_timeline_is_playing (timeline))
17236         clutter_timeline_stop (timeline);
17237
17238       g_signal_handler_disconnect (clos->transition, clos->completed_id);
17239
17240       g_object_unref (clos->transition);
17241       g_free (clos->name);
17242
17243       g_slice_free (TransitionClosure, clos);
17244     }
17245 }
17246
17247 static void
17248 on_transition_completed (ClutterTransition *transition,
17249                          TransitionClosure *clos)
17250 {
17251   ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
17252   ClutterActor *actor = clos->actor;
17253   ClutterAnimationInfo *info;
17254   gint n_repeats, cur_repeat;
17255
17256   info = _clutter_actor_get_animation_info (actor);
17257
17258   /* reset the caches used by animations */
17259   clutter_actor_store_content_box (actor, NULL);
17260
17261   /* ensure that we remove the transition only at the end
17262    * of its run; we emit ::completed for every repeat
17263    */
17264   n_repeats = clutter_timeline_get_repeat_count (timeline);
17265   cur_repeat = clutter_timeline_get_current_repeat (timeline);
17266
17267   if (cur_repeat == n_repeats)
17268     {
17269       if (clutter_transition_get_remove_on_complete (transition))
17270         {
17271           /* we take a reference here because removing the closure
17272            * will release the reference on the transition, and we
17273            * want the transition to survive the signal emission;
17274            * the master clock will release the last reference at
17275            * the end of the frame processing.
17276            */
17277           g_object_ref (transition);
17278           g_hash_table_remove (info->transitions, clos->name);
17279         }
17280     }
17281
17282   /* if it's the last transition then we clean up */
17283   if (g_hash_table_size (info->transitions) == 0)
17284     {
17285       g_hash_table_unref (info->transitions);
17286       info->transitions = NULL;
17287
17288       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17289                     _clutter_actor_get_debug_name (actor));
17290
17291       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17292     }
17293 }
17294
17295 void
17296 _clutter_actor_update_transition (ClutterActor *actor,
17297                                   GParamSpec   *pspec,
17298                                   ...)
17299 {
17300   TransitionClosure *clos;
17301   ClutterTimeline *timeline;
17302   ClutterInterval *interval;
17303   const ClutterAnimationInfo *info;
17304   va_list var_args;
17305   GType ptype;
17306   GValue initial = G_VALUE_INIT;
17307   GValue final = G_VALUE_INIT;
17308   char *error = NULL;
17309
17310   info = _clutter_actor_get_animation_info_or_defaults (actor);
17311
17312   if (info->transitions == NULL)
17313     return;
17314
17315   clos = g_hash_table_lookup (info->transitions, pspec->name);
17316   if (clos == NULL)
17317     return;
17318
17319   timeline = CLUTTER_TIMELINE (clos->transition);
17320
17321   va_start (var_args, pspec);
17322
17323   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17324
17325   g_value_init (&initial, ptype);
17326   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17327                                         pspec->name,
17328                                         &initial);
17329
17330   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17331   if (error != NULL)
17332     {
17333       g_critical ("%s: %s", G_STRLOC, error);
17334       g_free (error);
17335       goto out;
17336     }
17337
17338   interval = clutter_transition_get_interval (clos->transition);
17339   clutter_interval_set_initial_value (interval, &initial);
17340   clutter_interval_set_final_value (interval, &final);
17341
17342   /* if we're updating with an easing duration of zero milliseconds,
17343    * we just jump the timeline to the end and let it run its course
17344    */
17345   if (info->cur_state != NULL &&
17346       info->cur_state->easing_duration != 0)
17347     {
17348       guint cur_duration = clutter_timeline_get_duration (timeline);
17349       ClutterAnimationMode cur_mode =
17350         clutter_timeline_get_progress_mode (timeline);
17351
17352       if (cur_duration != info->cur_state->easing_duration)
17353         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17354
17355       if (cur_mode != info->cur_state->easing_mode)
17356         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17357
17358       clutter_timeline_rewind (timeline);
17359     }
17360   else
17361     {
17362       guint duration = clutter_timeline_get_duration (timeline);
17363
17364       clutter_timeline_advance (timeline, duration);
17365     }
17366
17367 out:
17368   g_value_unset (&initial);
17369   g_value_unset (&final);
17370
17371   va_end (var_args);
17372 }
17373
17374 /*< private >*
17375  * _clutter_actor_create_transition:
17376  * @actor: a #ClutterActor
17377  * @pspec: the property used for the transition
17378  * @...: initial and final state
17379  *
17380  * Creates a #ClutterTransition for the property represented by @pspec.
17381  *
17382  * Return value: a #ClutterTransition
17383  */
17384 ClutterTransition *
17385 _clutter_actor_create_transition (ClutterActor *actor,
17386                                   GParamSpec   *pspec,
17387                                   ...)
17388 {
17389   ClutterAnimationInfo *info;
17390   ClutterTransition *res = NULL;
17391   gboolean call_restore = FALSE;
17392   TransitionClosure *clos;
17393   va_list var_args;
17394
17395   info = _clutter_actor_get_animation_info (actor);
17396
17397   /* XXX - this will go away in 2.0
17398    *
17399    * if no state has been pushed, we assume that the easing state is
17400    * in "compatibility mode": all transitions have a duration of 0
17401    * msecs, which means that they happen immediately. in Clutter 2.0
17402    * this will turn into a g_assert(info->states != NULL), as every
17403    * actor will start with a predefined easing state
17404    */
17405   if (info->states == NULL)
17406     {
17407       clutter_actor_save_easing_state (actor);
17408       clutter_actor_set_easing_duration (actor, 0);
17409       call_restore = TRUE;
17410     }
17411
17412   if (info->transitions == NULL)
17413     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17414                                                NULL,
17415                                                transition_closure_free);
17416
17417   va_start (var_args, pspec);
17418
17419   clos = g_hash_table_lookup (info->transitions, pspec->name);
17420   if (clos == NULL)
17421     {
17422       ClutterTimeline *timeline;
17423       ClutterInterval *interval;
17424       GValue initial = G_VALUE_INIT;
17425       GValue final = G_VALUE_INIT;
17426       GType ptype;
17427       char *error;
17428
17429       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17430
17431       G_VALUE_COLLECT_INIT (&initial, ptype,
17432                             var_args, 0,
17433                             &error);
17434       if (error != NULL)
17435         {
17436           g_critical ("%s: %s", G_STRLOC, error);
17437           g_free (error);
17438           goto out;
17439         }
17440
17441       G_VALUE_COLLECT_INIT (&final, ptype,
17442                             var_args, 0,
17443                             &error);
17444
17445       if (error != NULL)
17446         {
17447           g_critical ("%s: %s", G_STRLOC, error);
17448           g_value_unset (&initial);
17449           g_free (error);
17450           goto out;
17451         }
17452
17453       /* if the current easing state has a duration of 0, then we don't
17454        * bother to create the transition, and we just set the final value
17455        * directly on the actor; we don't go through the Animatable
17456        * interface because we know we got here through an animatable
17457        * property.
17458        */
17459       if (info->cur_state->easing_duration == 0)
17460         {
17461           clutter_actor_set_animatable_property (actor,
17462                                                  pspec->param_id,
17463                                                  &final,
17464                                                  pspec);
17465           g_value_unset (&initial);
17466           g_value_unset (&final);
17467
17468           goto out;
17469         }
17470
17471       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17472
17473       g_value_unset (&initial);
17474       g_value_unset (&final);
17475
17476       res = clutter_property_transition_new (pspec->name);
17477
17478       clutter_transition_set_interval (res, interval);
17479       clutter_transition_set_remove_on_complete (res, TRUE);
17480
17481       timeline = CLUTTER_TIMELINE (res);
17482       clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17483       clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17484       clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17485
17486       /* this will start the transition as well */
17487       clutter_actor_add_transition (actor, pspec->name, res);
17488
17489       /* the actor now owns the transition */
17490       g_object_unref (res);
17491     }
17492   else
17493     res = clos->transition;
17494
17495 out:
17496   if (call_restore)
17497     clutter_actor_restore_easing_state (actor);
17498
17499   va_end (var_args);
17500
17501   return res;
17502 }
17503
17504 /**
17505  * clutter_actor_add_transition:
17506  * @self: a #ClutterActor
17507  * @name: the name of the transition to add
17508  * @transition: the #ClutterTransition to add
17509  *
17510  * Adds a @transition to the #ClutterActor's list of animations.
17511  *
17512  * The @name string is a per-actor unique identifier of the @transition: only
17513  * one #ClutterTransition can be associated to the specified @name.
17514  *
17515  * The @transition will be started once added.
17516  *
17517  * This function will take a reference on the @transition.
17518  *
17519  * This function is usually called implicitly when modifying an animatable
17520  * property.
17521  *
17522  * Since: 1.10
17523  */
17524 void
17525 clutter_actor_add_transition (ClutterActor      *self,
17526                               const char        *name,
17527                               ClutterTransition *transition)
17528 {
17529   ClutterTimeline *timeline;
17530   TransitionClosure *clos;
17531   ClutterAnimationInfo *info;
17532
17533   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17534   g_return_if_fail (name != NULL);
17535   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17536
17537   info = _clutter_actor_get_animation_info (self);
17538
17539   if (info->transitions == NULL)
17540     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17541                                                NULL,
17542                                                transition_closure_free);
17543
17544   if (g_hash_table_lookup (info->transitions, name) != NULL)
17545     {
17546       g_warning ("A transition with name '%s' already exists for "
17547                  "the actor '%s'",
17548                  name,
17549                  _clutter_actor_get_debug_name (self));
17550       return;
17551     }
17552
17553   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17554
17555   timeline = CLUTTER_TIMELINE (transition);
17556
17557   clos = g_slice_new (TransitionClosure);
17558   clos->actor = self;
17559   clos->transition = g_object_ref (transition);
17560   clos->name = g_strdup (name);
17561   clos->completed_id = g_signal_connect (timeline, "completed",
17562                                          G_CALLBACK (on_transition_completed),
17563                                          clos);
17564
17565   CLUTTER_NOTE (ANIMATION,
17566                 "Adding transition '%s' [%p] to actor '%s'",
17567                 clos->name,
17568                 clos->transition,
17569                 _clutter_actor_get_debug_name (self));
17570
17571   g_hash_table_insert (info->transitions, clos->name, clos);
17572   clutter_timeline_start (timeline);
17573 }
17574
17575 /**
17576  * clutter_actor_remove_transition:
17577  * @self: a #ClutterActor
17578  * @name: the name of the transition to remove
17579  *
17580  * Removes the transition stored inside a #ClutterActor using @name
17581  * identifier.
17582  *
17583  * If the transition is currently in progress, it will be stopped.
17584  *
17585  * This function releases the reference acquired when the transition
17586  * was added to the #ClutterActor.
17587  *
17588  * Since: 1.10
17589  */
17590 void
17591 clutter_actor_remove_transition (ClutterActor *self,
17592                                  const char   *name)
17593 {
17594   const ClutterAnimationInfo *info;
17595
17596   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17597   g_return_if_fail (name != NULL);
17598
17599   info = _clutter_actor_get_animation_info_or_defaults (self);
17600
17601   if (info->transitions == NULL)
17602     return;
17603
17604   g_hash_table_remove (info->transitions, name);
17605 }
17606
17607 /**
17608  * clutter_actor_remove_all_transitions:
17609  * @self: a #ClutterActor
17610  *
17611  * Removes all transitions associated to @self.
17612  *
17613  * Since: 1.10
17614  */
17615 void
17616 clutter_actor_remove_all_transitions (ClutterActor *self)
17617 {
17618   const ClutterAnimationInfo *info;
17619
17620   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17621
17622   info = _clutter_actor_get_animation_info_or_defaults (self);
17623   if (info->transitions == NULL)
17624     return;
17625
17626   g_hash_table_remove_all (info->transitions);
17627 }
17628
17629 /**
17630  * clutter_actor_set_easing_duration:
17631  * @self: a #ClutterActor
17632  * @msecs: the duration of the easing, or %NULL
17633  *
17634  * Sets the duration of the tweening for animatable properties
17635  * of @self for the current easing state.
17636  *
17637  * Since: 1.10
17638  */
17639 void
17640 clutter_actor_set_easing_duration (ClutterActor *self,
17641                                    guint         msecs)
17642 {
17643   ClutterAnimationInfo *info;
17644
17645   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17646
17647   info = _clutter_actor_get_animation_info (self);
17648
17649   if (info->cur_state == NULL)
17650     {
17651       g_warning ("You must call clutter_actor_save_easing_state() prior "
17652                  "to calling clutter_actor_set_easing_duration().");
17653       return;
17654     }
17655
17656   if (info->cur_state->easing_duration != msecs)
17657     info->cur_state->easing_duration = msecs;
17658 }
17659
17660 /**
17661  * clutter_actor_get_easing_duration:
17662  * @self: a #ClutterActor
17663  *
17664  * Retrieves the duration of the tweening for animatable
17665  * properties of @self for the current easing state.
17666  *
17667  * Return value: the duration of the tweening, in milliseconds
17668  *
17669  * Since: 1.10
17670  */
17671 guint
17672 clutter_actor_get_easing_duration (ClutterActor *self)
17673 {
17674   const ClutterAnimationInfo *info;
17675
17676   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17677
17678   info = _clutter_actor_get_animation_info_or_defaults (self);
17679
17680   if (info->cur_state != NULL)
17681     return info->cur_state->easing_duration;
17682
17683   return 0;
17684 }
17685
17686 /**
17687  * clutter_actor_set_easing_mode:
17688  * @self: a #ClutterActor
17689  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17690  *
17691  * Sets the easing mode for the tweening of animatable properties
17692  * of @self.
17693  *
17694  * Since: 1.10
17695  */
17696 void
17697 clutter_actor_set_easing_mode (ClutterActor         *self,
17698                                ClutterAnimationMode  mode)
17699 {
17700   ClutterAnimationInfo *info;
17701
17702   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17703   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17704   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17705
17706   info = _clutter_actor_get_animation_info (self);
17707
17708   if (info->cur_state == NULL)
17709     {
17710       g_warning ("You must call clutter_actor_save_easing_state() prior "
17711                  "to calling clutter_actor_set_easing_mode().");
17712       return;
17713     }
17714
17715   if (info->cur_state->easing_mode != mode)
17716     info->cur_state->easing_mode = mode;
17717 }
17718
17719 /**
17720  * clutter_actor_get_easing_mode:
17721  * @self: a #ClutterActor
17722  *
17723  * Retrieves the easing mode for the tweening of animatable properties
17724  * of @self for the current easing state.
17725  *
17726  * Return value: an easing mode
17727  *
17728  * Since: 1.10
17729  */
17730 ClutterAnimationMode
17731 clutter_actor_get_easing_mode (ClutterActor *self)
17732 {
17733   const ClutterAnimationInfo *info;
17734
17735   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17736
17737   info = _clutter_actor_get_animation_info_or_defaults (self);
17738
17739   if (info->cur_state != NULL)
17740     return info->cur_state->easing_mode;
17741
17742   return CLUTTER_EASE_OUT_CUBIC;
17743 }
17744
17745 /**
17746  * clutter_actor_set_easing_delay:
17747  * @self: a #ClutterActor
17748  * @msecs: the delay before the start of the tweening, in milliseconds
17749  *
17750  * Sets the delay that should be applied before tweening animatable
17751  * properties.
17752  *
17753  * Since: 1.10
17754  */
17755 void
17756 clutter_actor_set_easing_delay (ClutterActor *self,
17757                                 guint         msecs)
17758 {
17759   ClutterAnimationInfo *info;
17760
17761   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17762
17763   info = _clutter_actor_get_animation_info (self);
17764
17765   if (info->cur_state == NULL)
17766     {
17767       g_warning ("You must call clutter_actor_save_easing_state() prior "
17768                  "to calling clutter_actor_set_easing_delay().");
17769       return;
17770     }
17771
17772   if (info->cur_state->easing_delay != msecs)
17773     info->cur_state->easing_delay = msecs;
17774 }
17775
17776 /**
17777  * clutter_actor_get_easing_delay:
17778  * @self: a #ClutterActor
17779  *
17780  * Retrieves the delay that should be applied when tweening animatable
17781  * properties.
17782  *
17783  * Return value: a delay, in milliseconds
17784  *
17785  * Since: 1.10
17786  */
17787 guint
17788 clutter_actor_get_easing_delay (ClutterActor *self)
17789 {
17790   const ClutterAnimationInfo *info;
17791
17792   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17793
17794   info = _clutter_actor_get_animation_info_or_defaults (self);
17795
17796   if (info->cur_state != NULL)
17797     return info->cur_state->easing_delay;
17798
17799   return 0;
17800 }
17801
17802 /**
17803  * clutter_actor_get_transition:
17804  * @self: a #ClutterActor
17805  * @name: the name of the transition
17806  *
17807  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17808  * transition @name.
17809  *
17810  * Transitions created for animatable properties use the name of the
17811  * property itself, for instance the code below:
17812  *
17813  * |[
17814  *   clutter_actor_set_easing_duration (actor, 1000);
17815  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17816  *
17817  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17818  *   g_signal_connect (transition, "completed",
17819  *                     G_CALLBACK (on_transition_complete),
17820  *                     actor);
17821  * ]|
17822  *
17823  * will call the <function>on_transition_complete</function> callback when
17824  * the transition is complete.
17825  *
17826  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17827  *   was found to match the passed name; the returned instance is owned
17828  *   by Clutter and it should not be freed
17829  *
17830  * Since: 1.10
17831  */
17832 ClutterTransition *
17833 clutter_actor_get_transition (ClutterActor *self,
17834                               const char   *name)
17835 {
17836   TransitionClosure *clos;
17837   const ClutterAnimationInfo *info;
17838
17839   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17840   g_return_val_if_fail (name != NULL, NULL);
17841
17842   info = _clutter_actor_get_animation_info_or_defaults (self);
17843   if (info->transitions == NULL)
17844     return NULL;
17845
17846   clos = g_hash_table_lookup (info->transitions, name);
17847   if (clos == NULL)
17848     return NULL;
17849
17850   return clos->transition;
17851 }
17852
17853 /**
17854  * clutter_actor_save_easing_state:
17855  * @self: a #ClutterActor
17856  *
17857  * Saves the current easing state for animatable properties, and creates
17858  * a new state with the default values for easing mode and duration.
17859  *
17860  * Since: 1.10
17861  */
17862 void
17863 clutter_actor_save_easing_state (ClutterActor *self)
17864 {
17865   ClutterAnimationInfo *info;
17866   AState new_state;
17867
17868   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17869
17870   info = _clutter_actor_get_animation_info (self);
17871
17872   if (info->states == NULL)
17873     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17874
17875   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17876   new_state.easing_duration = 250;
17877   new_state.easing_delay = 0;
17878
17879   g_array_append_val (info->states, new_state);
17880
17881   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17882 }
17883
17884 /**
17885  * clutter_actor_restore_easing_state:
17886  * @self: a #ClutterActor
17887  *
17888  * Restores the easing state as it was prior to a call to
17889  * clutter_actor_save_easing_state().
17890  *
17891  * Since: 1.10
17892  */
17893 void
17894 clutter_actor_restore_easing_state (ClutterActor *self)
17895 {
17896   ClutterAnimationInfo *info;
17897
17898   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17899
17900   info = _clutter_actor_get_animation_info (self);
17901
17902   if (info->states == NULL)
17903     {
17904       g_critical ("The function clutter_actor_restore_easing_state() has "
17905                   "called without a previous call to "
17906                   "clutter_actor_save_easing_state().");
17907       return;
17908     }
17909
17910   g_array_remove_index (info->states, info->states->len - 1);
17911
17912   if (info->states->len > 0)
17913     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17914   else
17915     {
17916       g_array_unref (info->states);
17917       info->states = NULL;
17918       info->cur_state = NULL;
17919     }
17920 }
17921
17922 /**
17923  * clutter_actor_set_content:
17924  * @self: a #ClutterActor
17925  * @content: (allow-none): a #ClutterContent, or %NULL
17926  *
17927  * Sets the contents of a #ClutterActor.
17928  *
17929  * Since: 1.10
17930  */
17931 void
17932 clutter_actor_set_content (ClutterActor   *self,
17933                            ClutterContent *content)
17934 {
17935   ClutterActorPrivate *priv;
17936
17937   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17938   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17939
17940   priv = self->priv;
17941
17942   if (priv->content != NULL)
17943     {
17944       _clutter_content_detached (priv->content, self);
17945       g_clear_object (&priv->content);
17946     }
17947
17948   priv->content = content;
17949
17950   if (priv->content != NULL)
17951     {
17952       g_object_ref (priv->content);
17953       _clutter_content_attached (priv->content, self);
17954     }
17955
17956   /* given that the content is always painted within the allocation,
17957    * we only need to queue a redraw here
17958    */
17959   clutter_actor_queue_redraw (self);
17960
17961   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17962
17963   /* if the content gravity is not resize-fill, and the new content has a
17964    * different preferred size than the previous one, then the content box
17965    * may have been changed. since we compute that lazily, we just notify
17966    * here, and let whomever watches :content-box do whatever they need to
17967    * do.
17968    */
17969   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17970     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17971 }
17972
17973 /**
17974  * clutter_actor_get_content:
17975  * @self: a #ClutterActor
17976  *
17977  * Retrieves the contents of @self.
17978  *
17979  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17980  *   or %NULL if none was set
17981  *
17982  * Since: 1.10
17983  */
17984 ClutterContent *
17985 clutter_actor_get_content (ClutterActor *self)
17986 {
17987   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17988
17989   return self->priv->content;
17990 }
17991
17992 /**
17993  * clutter_actor_set_content_gravity:
17994  * @self: a #ClutterActor
17995  * @gravity: the #ClutterContentGravity
17996  *
17997  * Sets the gravity of the #ClutterContent used by @self.
17998  *
17999  * See the description of the #ClutterActor:content-gravity property for
18000  * more information.
18001  *
18002  * The #ClutterActor:content-gravity property is animatable.
18003  *
18004  * Since: 1.10
18005  */
18006 void
18007 clutter_actor_set_content_gravity (ClutterActor *self,
18008                                    ClutterContentGravity  gravity)
18009 {
18010   ClutterActorPrivate *priv;
18011
18012   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18013
18014   priv = self->priv;
18015
18016   if (priv->content_gravity == gravity)
18017     return;
18018
18019   priv->content_box_valid = FALSE;
18020
18021   if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
18022     {
18023       ClutterActorBox from_box, to_box;
18024
18025       clutter_actor_get_content_box (self, &from_box);
18026
18027       priv->content_gravity = gravity;
18028
18029       clutter_actor_get_content_box (self, &to_box);
18030
18031       _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
18032                                         &from_box,
18033                                         &to_box);
18034     }
18035   else
18036     {
18037       ClutterActorBox to_box;
18038
18039       priv->content_gravity = gravity;
18040
18041       clutter_actor_get_content_box (self, &to_box);
18042
18043       _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
18044                                         &to_box);
18045     }
18046
18047   clutter_actor_queue_redraw (self);
18048
18049   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
18050 }
18051
18052 /**
18053  * clutter_actor_get_content_gravity:
18054  * @self: a #ClutterActor
18055  *
18056  * Retrieves the content gravity as set using
18057  * clutter_actor_get_content_gravity().
18058  *
18059  * Return value: the content gravity
18060  *
18061  * Since: 1.10
18062  */
18063 ClutterContentGravity
18064 clutter_actor_get_content_gravity (ClutterActor *self)
18065 {
18066   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
18067                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
18068
18069   return self->priv->content_gravity;
18070 }
18071
18072 /**
18073  * clutter_actor_get_content_box:
18074  * @self: a #ClutterActor
18075  * @box: (out caller-allocates): the return location for the bounding
18076  *   box for the #ClutterContent
18077  *
18078  * Retrieves the bounding box for the #ClutterContent of @self.
18079  *
18080  * The bounding box is relative to the actor's allocation.
18081  *
18082  * If no #ClutterContent is set for @self, or if @self has not been
18083  * allocated yet, then the result is undefined.
18084  *
18085  * The content box is guaranteed to be, at most, as big as the allocation
18086  * of the #ClutterActor.
18087  *
18088  * If the #ClutterContent used by the actor has a preferred size, then
18089  * it is possible to modify the content box by using the
18090  * #ClutterActor:content-gravity property.
18091  *
18092  * Since: 1.10
18093  */
18094 void
18095 clutter_actor_get_content_box (ClutterActor    *self,
18096                                ClutterActorBox *box)
18097 {
18098   ClutterActorPrivate *priv;
18099   gfloat content_w, content_h;
18100   gfloat alloc_w, alloc_h;
18101
18102   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18103   g_return_if_fail (box != NULL);
18104
18105   priv = self->priv;
18106
18107   box->x1 = 0.f;
18108   box->y1 = 0.f;
18109   box->x2 = priv->allocation.x2 - priv->allocation.x1;
18110   box->y2 = priv->allocation.y2 - priv->allocation.y1;
18111
18112   if (priv->content_box_valid)
18113     {
18114       *box = priv->content_box;
18115       return;
18116     }
18117
18118   /* no need to do any more work */
18119   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18120     return;
18121
18122   if (priv->content == NULL)
18123     return;
18124
18125   /* if the content does not have a preferred size then there is
18126    * no point in computing the content box
18127    */
18128   if (!clutter_content_get_preferred_size (priv->content,
18129                                            &content_w,
18130                                            &content_h))
18131     return;
18132
18133   alloc_w = box->x2;
18134   alloc_h = box->y2;
18135
18136   switch (priv->content_gravity)
18137     {
18138     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
18139       box->x2 = box->x1 + MIN (content_w, alloc_w);
18140       box->y2 = box->y1 + MIN (content_h, alloc_h);
18141       break;
18142
18143     case CLUTTER_CONTENT_GRAVITY_TOP:
18144       if (alloc_w > content_w)
18145         {
18146           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18147           box->x2 = box->x1 + content_w;
18148         }
18149       box->y2 = box->y1 + MIN (content_h, alloc_h);
18150       break;
18151
18152     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
18153       if (alloc_w > content_w)
18154         {
18155           box->x1 += (alloc_w - content_w);
18156           box->x2 = box->x1 + content_w;
18157         }
18158       box->y2 = box->y1 + MIN (content_h, alloc_h);
18159       break;
18160
18161     case CLUTTER_CONTENT_GRAVITY_LEFT:
18162       box->x2 = box->x1 + MIN (content_w, alloc_w);
18163       if (alloc_h > content_h)
18164         {
18165           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18166           box->y2 = box->y1 + content_h;
18167         }
18168       break;
18169
18170     case CLUTTER_CONTENT_GRAVITY_CENTER:
18171       if (alloc_w > content_w)
18172         {
18173           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18174           box->x2 = box->x1 + content_w;
18175         }
18176       if (alloc_h > content_h)
18177         {
18178           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18179           box->y2 = box->y1 + content_h;
18180         }
18181       break;
18182
18183     case CLUTTER_CONTENT_GRAVITY_RIGHT:
18184       if (alloc_w > content_w)
18185         {
18186           box->x1 += (alloc_w - content_w);
18187           box->x2 = box->x1 + content_w;
18188         }
18189       if (alloc_h > content_h)
18190         {
18191           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18192           box->y2 = box->y1 + content_h;
18193         }
18194       break;
18195
18196     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18197       box->x2 = box->x1 + MIN (content_w, alloc_w);
18198       if (alloc_h > content_h)
18199         {
18200           box->y1 += (alloc_h - content_h);
18201           box->y2 = box->y1 + content_h;
18202         }
18203       break;
18204
18205     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18206       if (alloc_w > content_w)
18207         {
18208           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18209           box->x2 = box->x1 + content_w;
18210         }
18211       if (alloc_h > content_h)
18212         {
18213           box->y1 += (alloc_h - content_h);
18214           box->y2 = box->y1 + content_h;
18215         }
18216       break;
18217
18218     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18219       if (alloc_w > content_w)
18220         {
18221           box->x1 += (alloc_w - content_w);
18222           box->x2 = box->x1 + content_w;
18223         }
18224       if (alloc_h > content_h)
18225         {
18226           box->y1 += (alloc_h - content_h);
18227           box->y2 = box->y1 + content_h;
18228         }
18229       break;
18230
18231     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18232       g_assert_not_reached ();
18233       break;
18234
18235     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18236       {
18237         double r_c = content_w / content_h;
18238
18239         if (r_c >= 1.0)
18240           {
18241             if ((alloc_w / r_c) > alloc_h)
18242               {
18243                 box->x1 = 0.f;
18244                 box->x2 = alloc_w;
18245
18246                 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18247                 box->y2 = box->y1 + (alloc_w / r_c);
18248               }
18249             else
18250               {
18251                 box->y1 = 0.f;
18252                 box->y2 = alloc_h;
18253
18254                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18255                 box->x2 = box->x1 + (alloc_h * r_c);
18256               }
18257           }
18258         else
18259           {
18260             if ((alloc_w / r_c) > alloc_h)
18261               {
18262                 box->y1 = 0.f;
18263                 box->y2 = alloc_h;
18264
18265                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18266                 box->x2 = box->x1 + (alloc_h * r_c);
18267               }
18268             else
18269               {
18270                 box->x1 = 0.f;
18271                 box->x2 = alloc_w;
18272
18273                 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18274                 box->y2 = box->y1 + (alloc_w / r_c);
18275               }
18276           }
18277
18278         CLUTTER_NOTE (LAYOUT,
18279                       "r_c: %.3f, r_a: %.3f\t"
18280                       "a: [%.2fx%.2f], c: [%.2fx%.2f]\t"
18281                       "b: [%.2f, %.2f, %.2f, %.2f]",
18282                       r_c, alloc_w / alloc_h,
18283                       alloc_w, alloc_h,
18284                       content_w, content_h,
18285                       box->x1, box->y1, box->x2, box->y2);
18286       }
18287       break;
18288     }
18289 }
18290
18291 /**
18292  * clutter_actor_set_content_scaling_filters:
18293  * @self: a #ClutterActor
18294  * @min_filter: the minification filter for the content
18295  * @mag_filter: the magnification filter for the content
18296  *
18297  * Sets the minification and magnification filter to be applied when
18298  * scaling the #ClutterActor:content of a #ClutterActor.
18299  *
18300  * The #ClutterActor:minification-filter will be used when reducing
18301  * the size of the content; the #ClutterActor:magnification-filter
18302  * will be used when increasing the size of the content.
18303  *
18304  * Since: 1.10
18305  */
18306 void
18307 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18308                                            ClutterScalingFilter  min_filter,
18309                                            ClutterScalingFilter  mag_filter)
18310 {
18311   ClutterActorPrivate *priv;
18312   gboolean changed;
18313   GObject *obj;
18314
18315   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18316
18317   priv = self->priv;
18318   obj = G_OBJECT (self);
18319
18320   g_object_freeze_notify (obj);
18321
18322   changed = FALSE;
18323
18324   if (priv->min_filter != min_filter)
18325     {
18326       priv->min_filter = min_filter;
18327       changed = TRUE;
18328
18329       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18330     }
18331
18332   if (priv->mag_filter != mag_filter)
18333     {
18334       priv->mag_filter = mag_filter;
18335       changed = TRUE;
18336
18337       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18338     }
18339
18340   if (changed)
18341     clutter_actor_queue_redraw (self);
18342
18343   g_object_thaw_notify (obj);
18344 }
18345
18346 /**
18347  * clutter_actor_get_content_scaling_filters:
18348  * @self: a #ClutterActor
18349  * @min_filter: (out) (allow-none): return location for the minification
18350  *   filter, or %NULL
18351  * @mag_filter: (out) (allow-none): return location for the magnification
18352  *   filter, or %NULL
18353  *
18354  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18355  *
18356  * Since: 1.10
18357  */
18358 void
18359 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18360                                            ClutterScalingFilter *min_filter,
18361                                            ClutterScalingFilter *mag_filter)
18362 {
18363   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18364
18365   if (min_filter != NULL)
18366     *min_filter = self->priv->min_filter;
18367
18368   if (mag_filter != NULL)
18369     *mag_filter = self->priv->mag_filter;
18370 }
18371
18372 /*
18373  * clutter_actor_queue_compute_expand:
18374  * @self: a #ClutterActor
18375  *
18376  * Invalidates the needs_x_expand and needs_y_expand flags on @self
18377  * and its parents up to the top-level actor.
18378  *
18379  * This function also queues a relayout if anything changed.
18380  */
18381 static inline void
18382 clutter_actor_queue_compute_expand (ClutterActor *self)
18383 {
18384   ClutterActor *parent;
18385   gboolean changed;
18386
18387   if (self->priv->needs_compute_expand)
18388     return;
18389
18390   changed = FALSE;
18391   parent = self;
18392   while (parent != NULL)
18393     {
18394       if (!parent->priv->needs_compute_expand)
18395         {
18396           parent->priv->needs_compute_expand = TRUE;
18397           changed = TRUE;
18398         }
18399
18400       parent = parent->priv->parent;
18401     }
18402
18403   if (changed)
18404     clutter_actor_queue_relayout (self);
18405 }
18406
18407 /**
18408  * clutter_actor_set_x_expand:
18409  * @self: a #ClutterActor
18410  * @expand: whether the actor should expand horizontally
18411  *
18412  * Sets whether a #ClutterActor should expand horizontally; this means
18413  * that layout manager should allocate extra space for the actor, if
18414  * possible.
18415  *
18416  * Setting an actor to expand will also make all its parent expand, so
18417  * that it's possible to build an actor tree and only set this flag on
18418  * its leaves and not on every single actor.
18419  *
18420  * Since: 1.12
18421  */
18422 void
18423 clutter_actor_set_x_expand (ClutterActor *self,
18424                             gboolean      expand)
18425 {
18426   ClutterLayoutInfo *info;
18427
18428   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18429
18430   expand = !!expand;
18431
18432   info = _clutter_actor_get_layout_info (self);
18433   if (info->x_expand != expand)
18434     {
18435       info->x_expand = expand;
18436
18437       self->priv->x_expand_set = TRUE;
18438
18439       clutter_actor_queue_compute_expand (self);
18440
18441       g_object_notify_by_pspec (G_OBJECT (self),
18442                                 obj_props[PROP_X_EXPAND]);
18443     }
18444 }
18445
18446 /**
18447  * clutter_actor_get_x_expand:
18448  * @self: a #ClutterActor
18449  *
18450  * Retrieves the value set with clutter_actor_set_x_expand().
18451  *
18452  * See also: clutter_actor_needs_expand()
18453  *
18454  * Return value: %TRUE if the actor has been set to expand
18455  *
18456  * Since: 1.12
18457  */
18458 gboolean
18459 clutter_actor_get_x_expand (ClutterActor *self)
18460 {
18461   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18462
18463   return _clutter_actor_get_layout_info_or_defaults (self)->x_expand;
18464 }
18465
18466 /**
18467  * clutter_actor_set_y_expand:
18468  * @self: a #ClutterActor
18469  * @expand: whether the actor should expand vertically
18470  *
18471  * Sets whether a #ClutterActor should expand horizontally; this means
18472  * that layout manager should allocate extra space for the actor, if
18473  * possible.
18474  *
18475  * Setting an actor to expand will also make all its parent expand, so
18476  * that it's possible to build an actor tree and only set this flag on
18477  * its leaves and not on every single actor.
18478  *
18479  * Since: 1.12
18480  */
18481 void
18482 clutter_actor_set_y_expand (ClutterActor *self,
18483                             gboolean      expand)
18484 {
18485   ClutterLayoutInfo *info;
18486
18487   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18488
18489   expand = !!expand;
18490
18491   info = _clutter_actor_get_layout_info (self);
18492   if (info->y_expand != expand)
18493     {
18494       info->y_expand = expand;
18495
18496       self->priv->y_expand_set = TRUE;
18497
18498       clutter_actor_queue_compute_expand (self);
18499
18500       g_object_notify_by_pspec (G_OBJECT (self),
18501                                 obj_props[PROP_Y_EXPAND]);
18502     }
18503 }
18504
18505 /**
18506  * clutter_actor_get_y_expand:
18507  * @self: a #ClutterActor
18508  *
18509  * Retrieves the value set with clutter_actor_set_y_expand().
18510  *
18511  * See also: clutter_actor_needs_expand()
18512  *
18513  * Return value: %TRUE if the actor has been set to expand
18514  *
18515  * Since: 1.12
18516  */
18517 gboolean
18518 clutter_actor_get_y_expand (ClutterActor *self)
18519 {
18520   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18521
18522   return _clutter_actor_get_layout_info_or_defaults (self)->y_expand;
18523 }
18524
18525 static void
18526 clutter_actor_compute_expand_recursive (ClutterActor *self,
18527                                         gboolean     *x_expand_p,
18528                                         gboolean     *y_expand_p)
18529 {
18530   ClutterActorIter iter;
18531   ClutterActor *child;
18532   gboolean x_expand, y_expand;
18533
18534   x_expand = y_expand = FALSE;
18535
18536   /* note that we don't recurse into children if we're already set to expand;
18537    * this avoids traversing the whole actor tree, even if it may lead to some
18538    * child left with the needs_compute_expand flag set.
18539    */
18540   clutter_actor_iter_init (&iter, self);
18541   while (clutter_actor_iter_next (&iter, &child))
18542     {
18543       x_expand = x_expand ||
18544         clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL);
18545
18546       y_expand = y_expand ||
18547         clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL);
18548     }
18549
18550   *x_expand_p = x_expand;
18551   *y_expand_p = y_expand;
18552 }
18553
18554 static void
18555 clutter_actor_compute_expand (ClutterActor *self)
18556 {
18557   if (self->priv->needs_compute_expand)
18558     {
18559       const ClutterLayoutInfo *info;
18560       gboolean x_expand, y_expand;
18561
18562       info = _clutter_actor_get_layout_info_or_defaults (self);
18563
18564       if (self->priv->x_expand_set)
18565         x_expand = info->x_expand;
18566       else
18567         x_expand = FALSE;
18568
18569       if (self->priv->y_expand_set)
18570         y_expand = info->y_expand;
18571       else
18572         y_expand = FALSE;
18573
18574       /* we don't need to recurse down to the children if the
18575        * actor has been forcibly set to expand
18576        */
18577       if (!(self->priv->x_expand_set && self->priv->y_expand_set))
18578         {
18579           if (self->priv->n_children != 0)
18580             {
18581               gboolean *x_expand_p, *y_expand_p;
18582               gboolean ignored = FALSE;
18583
18584               x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand;
18585               y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand;
18586
18587               clutter_actor_compute_expand_recursive (self,
18588                                                       x_expand_p,
18589                                                       y_expand_p);
18590             }
18591         }
18592
18593       self->priv->needs_compute_expand = FALSE;
18594       self->priv->needs_x_expand = (x_expand != FALSE);
18595       self->priv->needs_y_expand = (y_expand != FALSE);
18596     }
18597 }
18598
18599 /**
18600  * clutter_actor_needs_expand:
18601  * @self: a #ClutterActor
18602  * @orientation: the direction of expansion
18603  *
18604  * Checks whether an actor, or any of its children, is set to expand
18605  * horizontally or vertically.
18606  *
18607  * This function should only be called by layout managers that can
18608  * assign extra space to their children.
18609  *
18610  * If you want to know whether the actor was explicitly set to expand,
18611  * use clutter_actor_get_x_expand() or clutter_actor_get_y_expand().
18612  *
18613  * Return value: %TRUE if the actor should expand
18614  *
18615  * Since: 1.12
18616  */
18617 gboolean
18618 clutter_actor_needs_expand (ClutterActor       *self,
18619                             ClutterOrientation  orientation)
18620 {
18621   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18622
18623   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18624     return FALSE;
18625
18626   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18627     return FALSE;
18628
18629   clutter_actor_compute_expand (self);
18630
18631   switch (orientation)
18632     {
18633     case CLUTTER_ORIENTATION_HORIZONTAL:
18634       return self->priv->needs_x_expand;
18635
18636     case CLUTTER_ORIENTATION_VERTICAL:
18637       return self->priv->needs_y_expand;
18638     }
18639
18640   return FALSE;
18641 }