Add _clutter_actor_peek_layout_info
[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-angle-x and #ClutterActor:rotation-center-x;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-angle-y and #ClutterActor:rotation-center-y;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-angle-z and #ClutterActor:rotation-center-z;</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-easing.h"
597 #include "clutter-effect-private.h"
598 #include "clutter-enum-types.h"
599 #include "clutter-fixed-layout.h"
600 #include "clutter-flatten-effect.h"
601 #include "clutter-interval.h"
602 #include "clutter-main.h"
603 #include "clutter-marshal.h"
604 #include "clutter-paint-nodes.h"
605 #include "clutter-paint-node-private.h"
606 #include "clutter-paint-volume-private.h"
607 #include "clutter-private.h"
608 #include "clutter-profile.h"
609 #include "clutter-property-transition.h"
610 #include "clutter-scriptable.h"
611 #include "clutter-script-private.h"
612 #include "clutter-stage-private.h"
613 #include "clutter-timeline.h"
614 #include "clutter-transition.h"
615 #include "clutter-units.h"
616
617 #include "deprecated/clutter-actor.h"
618 #include "deprecated/clutter-behaviour.h"
619 #include "deprecated/clutter-container.h"
620
621 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
622 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
623
624 /* Internal enum used to control mapped state update.  This is a hint
625  * which indicates when to do something other than just enforce
626  * invariants.
627  */
628 typedef enum {
629   MAP_STATE_CHECK,           /* just enforce invariants. */
630   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
631                               * used when about to unparent.
632                               */
633   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
634                               * used to set mapped on toplevels.
635                               */
636   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
637                               * used just before unmapping parent.
638                               */
639 } MapStateChange;
640
641 /* 3 entries should be a good compromise, few layout managers
642  * will ask for 3 different preferred size in each allocation cycle */
643 #define N_CACHED_SIZE_REQUESTS 3
644
645 struct _ClutterActorPrivate
646 {
647   /* request mode */
648   ClutterRequestMode request_mode;
649
650   /* our cached size requests for different width / height */
651   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
652   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
653
654   /* An age of 0 means the entry is not set */
655   guint cached_height_age;
656   guint cached_width_age;
657
658   /* the bounding box of the actor, relative to the parent's
659    * allocation
660    */
661   ClutterActorBox allocation;
662   ClutterAllocationFlags allocation_flags;
663
664   /* clip, in actor coordinates */
665   cairo_rectangle_t clip;
666
667   /* the cached transformation matrix; see apply_transform() */
668   CoglMatrix transform;
669
670   guint8 opacity;
671   gint opacity_override;
672
673   ClutterOffscreenRedirect offscreen_redirect;
674
675   /* This is an internal effect used to implement the
676      offscreen-redirect property */
677   ClutterEffect *flatten_effect;
678
679   /* scene graph */
680   ClutterActor *parent;
681   ClutterActor *prev_sibling;
682   ClutterActor *next_sibling;
683   ClutterActor *first_child;
684   ClutterActor *last_child;
685
686   gint n_children;
687
688   /* tracks whenever the children of an actor are changed; the
689    * age is incremented by 1 whenever an actor is added or
690    * removed. the age is not incremented when the first or the
691    * last child pointers are changed, or when grandchildren of
692    * an actor are changed.
693    */
694   gint age;
695
696   gchar *name; /* a non-unique name, used for debugging */
697   guint32 id; /* unique id, used for backward compatibility */
698
699   gint32 pick_id; /* per-stage unique id, used for picking */
700
701   /* a back-pointer to the Pango context that we can use
702    * to create pre-configured PangoLayout
703    */
704   PangoContext *pango_context;
705
706   /* the text direction configured for this child - either by
707    * application code, or by the actor's parent
708    */
709   ClutterTextDirection text_direction;
710
711   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
712   gint internal_child;
713
714   /* meta classes */
715   ClutterMetaGroup *actions;
716   ClutterMetaGroup *constraints;
717   ClutterMetaGroup *effects;
718
719   /* delegate object used to allocate the children of this actor */
720   ClutterLayoutManager *layout_manager;
721
722   /* delegate object used to paint the contents of this actor */
723   ClutterContent *content;
724
725   ClutterActorBox content_box;
726   ClutterContentGravity content_gravity;
727   ClutterScalingFilter min_filter;
728   ClutterScalingFilter mag_filter;
729
730   /* used when painting, to update the paint volume */
731   ClutterEffect *current_effect;
732
733   /* This is used to store an effect which needs to be redrawn. A
734      redraw can be queued to start from a particular effect. This is
735      used by parametrised effects that can cache an image of the
736      actor. If a parameter of the effect changes then it only needs to
737      redraw the cached image, not the actual actor. The pointer is
738      only valid if is_dirty == TRUE. If the pointer is NULL then the
739      whole actor is dirty. */
740   ClutterEffect *effect_to_redraw;
741
742   /* This is used when painting effects to implement the
743      clutter_actor_continue_paint() function. It points to the node in
744      the list of effects that is next in the chain */
745   const GList *next_effect_to_paint;
746
747   ClutterPaintVolume paint_volume;
748
749   /* NB: This volume isn't relative to this actor, it is in eye
750    * coordinates so that it can remain valid after the actor changes.
751    */
752   ClutterPaintVolume last_paint_volume;
753
754   ClutterStageQueueRedrawEntry *queue_redraw_entry;
755
756   ClutterColor bg_color;
757
758 #ifdef CLUTTER_ENABLE_DEBUG
759   /* a string used for debugging messages */
760   gchar *debug_name;
761 #endif
762
763   /* bitfields */
764
765   /* fixed position and sizes */
766   guint position_set                : 1;
767   guint min_width_set               : 1;
768   guint min_height_set              : 1;
769   guint natural_width_set           : 1;
770   guint natural_height_set          : 1;
771   /* cached request is invalid (implies allocation is too) */
772   guint needs_width_request         : 1;
773   /* cached request is invalid (implies allocation is too) */
774   guint needs_height_request        : 1;
775   /* cached allocation is invalid (request has changed, probably) */
776   guint needs_allocation            : 1;
777   guint show_on_set_parent          : 1;
778   guint has_clip                    : 1;
779   guint clip_to_allocation          : 1;
780   guint enable_model_view_transform : 1;
781   guint enable_paint_unmapped       : 1;
782   guint has_pointer                 : 1;
783   guint propagated_one_redraw       : 1;
784   guint paint_volume_valid          : 1;
785   guint last_paint_volume_valid     : 1;
786   guint in_clone_paint              : 1;
787   guint transform_valid             : 1;
788   /* This is TRUE if anything has queued a redraw since we were last
789      painted. In this case effect_to_redraw will point to an effect
790      the redraw was queued from or it will be NULL if the redraw was
791      queued without an effect. */
792   guint is_dirty                    : 1;
793   guint bg_color_set                : 1;
794   guint content_box_valid           : 1;
795   guint x_expand_set                : 1;
796   guint y_expand_set                : 1;
797   guint needs_compute_expand        : 1;
798   guint needs_x_expand              : 1;
799   guint needs_y_expand              : 1;
800 };
801
802 enum
803 {
804   PROP_0,
805
806   PROP_NAME,
807
808   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
809    * when set they force a size request, when gotten they
810    * get the allocation if the allocation is valid, and the
811    * request otherwise
812    */
813   PROP_X,
814   PROP_Y,
815   PROP_WIDTH,
816   PROP_HEIGHT,
817
818   PROP_POSITION,
819   PROP_SIZE,
820
821   /* Then the rest of these size-related properties are the "actual"
822    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
823    */
824   PROP_FIXED_X,
825   PROP_FIXED_Y,
826
827   PROP_FIXED_POSITION_SET,
828
829   PROP_MIN_WIDTH,
830   PROP_MIN_WIDTH_SET,
831
832   PROP_MIN_HEIGHT,
833   PROP_MIN_HEIGHT_SET,
834
835   PROP_NATURAL_WIDTH,
836   PROP_NATURAL_WIDTH_SET,
837
838   PROP_NATURAL_HEIGHT,
839   PROP_NATURAL_HEIGHT_SET,
840
841   PROP_REQUEST_MODE,
842
843   /* Allocation properties are read-only */
844   PROP_ALLOCATION,
845
846   PROP_DEPTH,
847
848   PROP_CLIP,
849   PROP_HAS_CLIP,
850   PROP_CLIP_TO_ALLOCATION,
851
852   PROP_OPACITY,
853
854   PROP_OFFSCREEN_REDIRECT,
855
856   PROP_VISIBLE,
857   PROP_MAPPED,
858   PROP_REALIZED,
859   PROP_REACTIVE,
860
861   PROP_SCALE_X,
862   PROP_SCALE_Y,
863   PROP_SCALE_CENTER_X,
864   PROP_SCALE_CENTER_Y,
865   PROP_SCALE_GRAVITY,
866
867   PROP_ROTATION_ANGLE_X,
868   PROP_ROTATION_ANGLE_Y,
869   PROP_ROTATION_ANGLE_Z,
870   PROP_ROTATION_CENTER_X,
871   PROP_ROTATION_CENTER_Y,
872   PROP_ROTATION_CENTER_Z,
873   /* This property only makes sense for the z rotation because the
874      others would depend on the actor having a size along the
875      z-axis */
876   PROP_ROTATION_CENTER_Z_GRAVITY,
877
878   PROP_ANCHOR_X,
879   PROP_ANCHOR_Y,
880   PROP_ANCHOR_GRAVITY,
881
882   PROP_SHOW_ON_SET_PARENT,
883
884   PROP_TEXT_DIRECTION,
885   PROP_HAS_POINTER,
886
887   PROP_ACTIONS,
888   PROP_CONSTRAINTS,
889   PROP_EFFECT,
890
891   PROP_LAYOUT_MANAGER,
892
893   PROP_X_EXPAND,
894   PROP_Y_EXPAND,
895   PROP_X_ALIGN,
896   PROP_Y_ALIGN,
897   PROP_MARGIN_TOP,
898   PROP_MARGIN_BOTTOM,
899   PROP_MARGIN_LEFT,
900   PROP_MARGIN_RIGHT,
901
902   PROP_BACKGROUND_COLOR,
903   PROP_BACKGROUND_COLOR_SET,
904
905   PROP_FIRST_CHILD,
906   PROP_LAST_CHILD,
907
908   PROP_CONTENT,
909   PROP_CONTENT_GRAVITY,
910   PROP_CONTENT_BOX,
911   PROP_MINIFICATION_FILTER,
912   PROP_MAGNIFICATION_FILTER,
913
914   PROP_LAST
915 };
916
917 static GParamSpec *obj_props[PROP_LAST];
918
919 enum
920 {
921   SHOW,
922   HIDE,
923   DESTROY,
924   PARENT_SET,
925   KEY_FOCUS_IN,
926   KEY_FOCUS_OUT,
927   PAINT,
928   PICK,
929   REALIZE,
930   UNREALIZE,
931   QUEUE_REDRAW,
932   QUEUE_RELAYOUT,
933   EVENT,
934   CAPTURED_EVENT,
935   BUTTON_PRESS_EVENT,
936   BUTTON_RELEASE_EVENT,
937   SCROLL_EVENT,
938   KEY_PRESS_EVENT,
939   KEY_RELEASE_EVENT,
940   MOTION_EVENT,
941   ENTER_EVENT,
942   LEAVE_EVENT,
943   ALLOCATION_CHANGED,
944   TRANSITIONS_COMPLETED,
945
946   LAST_SIGNAL
947 };
948
949 static guint actor_signals[LAST_SIGNAL] = { 0, };
950
951 typedef struct _TransitionClosure
952 {
953   ClutterActor *actor;
954   ClutterTransition *transition;
955   gchar *name;
956   gulong completed_id;
957 } TransitionClosure;
958
959 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
960 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
961 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
962 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
963
964 /* These setters are all static for now, maybe they should be in the
965  * public API, but they are perhaps obscure enough to leave only as
966  * properties
967  */
968 static void clutter_actor_set_min_width          (ClutterActor *self,
969                                                   gfloat        min_width);
970 static void clutter_actor_set_min_height         (ClutterActor *self,
971                                                   gfloat        min_height);
972 static void clutter_actor_set_natural_width      (ClutterActor *self,
973                                                   gfloat        natural_width);
974 static void clutter_actor_set_natural_height     (ClutterActor *self,
975                                                   gfloat        natural_height);
976 static void clutter_actor_set_min_width_set      (ClutterActor *self,
977                                                   gboolean      use_min_width);
978 static void clutter_actor_set_min_height_set     (ClutterActor *self,
979                                                   gboolean      use_min_height);
980 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
981                                                   gboolean  use_natural_width);
982 static void clutter_actor_set_natural_height_set (ClutterActor *self,
983                                                   gboolean  use_natural_height);
984 static void clutter_actor_update_map_state       (ClutterActor  *self,
985                                                   MapStateChange change);
986 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
987
988 /* Helper routines for managing anchor coords */
989 static void clutter_anchor_coord_get_units (ClutterActor      *self,
990                                             const AnchorCoord *coord,
991                                             gfloat            *x,
992                                             gfloat            *y,
993                                             gfloat            *z);
994 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
995                                             gfloat             x,
996                                             gfloat             y,
997                                             gfloat             z);
998
999 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
1000 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
1001                                                         ClutterGravity     gravity);
1002
1003 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
1004
1005 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
1006
1007 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
1008                                                                ClutterActor *ancestor,
1009                                                                CoglMatrix *matrix);
1010
1011 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
1012
1013 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
1014
1015 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
1016                                                                 const ClutterColor *color);
1017
1018 static void on_layout_manager_changed (ClutterLayoutManager *manager,
1019                                        ClutterActor         *self);
1020
1021 static inline void clutter_actor_queue_compute_expand (ClutterActor *self);
1022
1023 /* Helper macro which translates by the anchor coord, applies the
1024    given transformation and then translates back */
1025 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
1026   gfloat _tx, _ty, _tz;                                                \
1027   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
1028   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
1029   { _transform; }                                                      \
1030   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
1031
1032 static GQuark quark_shader_data = 0;
1033 static GQuark quark_actor_layout_info = 0;
1034 static GQuark quark_actor_transform_info = 0;
1035 static GQuark quark_actor_animation_info = 0;
1036
1037 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
1038                          clutter_actor,
1039                          G_TYPE_INITIALLY_UNOWNED,
1040                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1041                                                 clutter_container_iface_init)
1042                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1043                                                 clutter_scriptable_iface_init)
1044                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1045                                                 clutter_animatable_iface_init)
1046                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1047                                                 atk_implementor_iface_init));
1048
1049 /*< private >
1050  * clutter_actor_get_debug_name:
1051  * @actor: a #ClutterActor
1052  *
1053  * Retrieves a printable name of @actor for debugging messages
1054  *
1055  * Return value: a string with a printable name
1056  */
1057 const gchar *
1058 _clutter_actor_get_debug_name (ClutterActor *actor)
1059 {
1060   ClutterActorPrivate *priv = actor->priv;
1061   const gchar *retval;
1062
1063 #ifdef CLUTTER_ENABLE_DEBUG
1064   if (G_UNLIKELY (priv->debug_name == NULL))
1065     {
1066       priv->debug_name = g_strdup_printf ("<%s>[<%s>:%p]",
1067                                           priv->name != NULL ? priv->name
1068                                                              : "unnamed",
1069                                           G_OBJECT_TYPE_NAME (actor),
1070                                           actor);
1071     }
1072
1073   retval = priv->debug_name;
1074 #else
1075   retval = priv->name != NULL
1076          ? priv->name
1077          : G_OBJECT_TYPE_NAME (actor);
1078 #endif
1079
1080   return retval;
1081 }
1082
1083 #ifdef CLUTTER_ENABLE_DEBUG
1084 /* XXX - this is for debugging only, remove once working (or leave
1085  * in only in some debug mode). Should leave it for a little while
1086  * until we're confident in the new map/realize/visible handling.
1087  */
1088 static inline void
1089 clutter_actor_verify_map_state (ClutterActor *self)
1090 {
1091   ClutterActorPrivate *priv = self->priv;
1092
1093   if (CLUTTER_ACTOR_IS_REALIZED (self))
1094     {
1095       /* all bets are off during reparent when we're potentially realized,
1096        * but should not be according to invariants
1097        */
1098       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1099         {
1100           if (priv->parent == NULL)
1101             {
1102               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1103                 {
1104                 }
1105               else
1106                 g_warning ("Realized non-toplevel actor '%s' should "
1107                            "have a parent",
1108                            _clutter_actor_get_debug_name (self));
1109             }
1110           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1111             {
1112               g_warning ("Realized actor %s has an unrealized parent %s",
1113                          _clutter_actor_get_debug_name (self),
1114                          _clutter_actor_get_debug_name (priv->parent));
1115             }
1116         }
1117     }
1118
1119   if (CLUTTER_ACTOR_IS_MAPPED (self))
1120     {
1121       if (!CLUTTER_ACTOR_IS_REALIZED (self))
1122         g_warning ("Actor '%s' is mapped but not realized",
1123                    _clutter_actor_get_debug_name (self));
1124
1125       /* remaining bets are off during reparent when we're potentially
1126        * mapped, but should not be according to invariants
1127        */
1128       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1129         {
1130           if (priv->parent == NULL)
1131             {
1132               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1133                 {
1134                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1135                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1136                     {
1137                       g_warning ("Toplevel actor '%s' is mapped "
1138                                  "but not visible",
1139                                  _clutter_actor_get_debug_name (self));
1140                     }
1141                 }
1142               else
1143                 {
1144                   g_warning ("Mapped actor '%s' should have a parent",
1145                              _clutter_actor_get_debug_name (self));
1146                 }
1147             }
1148           else
1149             {
1150               ClutterActor *iter = self;
1151
1152               /* check for the enable_paint_unmapped flag on the actor
1153                * and parents; if the flag is enabled at any point of this
1154                * branch of the scene graph then all the later checks
1155                * become pointless
1156                */
1157               while (iter != NULL)
1158                 {
1159                   if (iter->priv->enable_paint_unmapped)
1160                     return;
1161
1162                   iter = iter->priv->parent;
1163                 }
1164
1165               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1166                 {
1167                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1168                              "is not visible",
1169                              _clutter_actor_get_debug_name (self),
1170                              _clutter_actor_get_debug_name (priv->parent));
1171                 }
1172
1173               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1174                 {
1175                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1176                              "is not realized",
1177                              _clutter_actor_get_debug_name (self),
1178                              _clutter_actor_get_debug_name (priv->parent));
1179                 }
1180
1181               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1182                 {
1183                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1184                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1185                                "parent '%s' is not mapped",
1186                                _clutter_actor_get_debug_name (self),
1187                                _clutter_actor_get_debug_name (priv->parent));
1188                 }
1189             }
1190         }
1191     }
1192 }
1193
1194 #endif /* CLUTTER_ENABLE_DEBUG */
1195
1196 static void
1197 clutter_actor_set_mapped (ClutterActor *self,
1198                           gboolean      mapped)
1199 {
1200   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1201     return;
1202
1203   if (mapped)
1204     {
1205       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1206       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1207     }
1208   else
1209     {
1210       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1211       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1212     }
1213 }
1214
1215 /* this function updates the mapped and realized states according to
1216  * invariants, in the appropriate order.
1217  */
1218 static void
1219 clutter_actor_update_map_state (ClutterActor  *self,
1220                                 MapStateChange change)
1221 {
1222   gboolean was_mapped;
1223
1224   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1225
1226   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1227     {
1228       /* the mapped flag on top-level actors must be set by the
1229        * per-backend implementation because it might be asynchronous.
1230        *
1231        * That is, the MAPPED flag on toplevels currently tracks the X
1232        * server mapped-ness of the window, while the expected behavior
1233        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1234        * This creates some weird complexity by breaking the invariant
1235        * that if we're visible and all ancestors shown then we are
1236        * also mapped - instead, we are mapped if all ancestors
1237        * _possibly excepting_ the stage are mapped. The stage
1238        * will map/unmap for example when it is minimized or
1239        * moved to another workspace.
1240        *
1241        * So, the only invariant on the stage is that if visible it
1242        * should be realized, and that it has to be visible to be
1243        * mapped.
1244        */
1245       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1246         clutter_actor_realize (self);
1247
1248       switch (change)
1249         {
1250         case MAP_STATE_CHECK:
1251           break;
1252
1253         case MAP_STATE_MAKE_MAPPED:
1254           g_assert (!was_mapped);
1255           clutter_actor_set_mapped (self, TRUE);
1256           break;
1257
1258         case MAP_STATE_MAKE_UNMAPPED:
1259           g_assert (was_mapped);
1260           clutter_actor_set_mapped (self, FALSE);
1261           break;
1262
1263         case MAP_STATE_MAKE_UNREALIZED:
1264           /* we only use MAKE_UNREALIZED in unparent,
1265            * and unparenting a stage isn't possible.
1266            * If someone wants to just unrealize a stage
1267            * then clutter_actor_unrealize() doesn't
1268            * go through this codepath.
1269            */
1270           g_warning ("Trying to force unrealize stage is not allowed");
1271           break;
1272         }
1273
1274       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1275           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1276           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1277         {
1278           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1279                      "it is somehow still mapped",
1280                      _clutter_actor_get_debug_name (self));
1281         }
1282     }
1283   else
1284     {
1285       ClutterActorPrivate *priv = self->priv;
1286       ClutterActor *parent = priv->parent;
1287       gboolean should_be_mapped;
1288       gboolean may_be_realized;
1289       gboolean must_be_realized;
1290
1291       should_be_mapped = FALSE;
1292       may_be_realized = TRUE;
1293       must_be_realized = FALSE;
1294
1295       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1296         {
1297           may_be_realized = FALSE;
1298         }
1299       else
1300         {
1301           /* Maintain invariant that if parent is mapped, and we are
1302            * visible, then we are mapped ...  unless parent is a
1303            * stage, in which case we map regardless of parent's map
1304            * state but do require stage to be visible and realized.
1305            *
1306            * If parent is realized, that does not force us to be
1307            * realized; but if parent is unrealized, that does force
1308            * us to be unrealized.
1309            *
1310            * The reason we don't force children to realize with
1311            * parents is _clutter_actor_rerealize(); if we require that
1312            * a realized parent means children are realized, then to
1313            * unrealize an actor we would have to unrealize its
1314            * parents, which would end up meaning unrealizing and
1315            * hiding the entire stage. So we allow unrealizing a
1316            * child (as long as that child is not mapped) while that
1317            * child still has a realized parent.
1318            *
1319            * Also, if we unrealize from leaf nodes to root, and
1320            * realize from root to leaf, the invariants are never
1321            * violated if we allow children to be unrealized
1322            * while parents are realized.
1323            *
1324            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1325            * to force us to unmap, even though parent is still
1326            * mapped. This is because we're unmapping from leaf nodes
1327            * up to root nodes.
1328            */
1329           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1330               change != MAP_STATE_MAKE_UNMAPPED)
1331             {
1332               gboolean parent_is_visible_realized_toplevel;
1333
1334               parent_is_visible_realized_toplevel =
1335                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1336                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1337                  CLUTTER_ACTOR_IS_REALIZED (parent));
1338
1339               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1340                   parent_is_visible_realized_toplevel)
1341                 {
1342                   must_be_realized = TRUE;
1343                   should_be_mapped = TRUE;
1344                 }
1345             }
1346
1347           /* if the actor has been set to be painted even if unmapped
1348            * then we should map it and check for realization as well;
1349            * this is an override for the branch of the scene graph
1350            * which begins with this node
1351            */
1352           if (priv->enable_paint_unmapped)
1353             {
1354               if (priv->parent == NULL)
1355                 g_warning ("Attempting to map an unparented actor '%s'",
1356                            _clutter_actor_get_debug_name (self));
1357
1358               should_be_mapped = TRUE;
1359               must_be_realized = TRUE;
1360             }
1361
1362           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1363             may_be_realized = FALSE;
1364         }
1365
1366       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1367         {
1368           if (parent == NULL)
1369             g_warning ("Attempting to map a child that does not "
1370                        "meet the necessary invariants: the actor '%s' "
1371                        "has no parent",
1372                        _clutter_actor_get_debug_name (self));
1373           else
1374             g_warning ("Attempting to map a child that does not "
1375                        "meet the necessary invariants: the actor '%s' "
1376                        "is parented to an unmapped actor '%s'",
1377                        _clutter_actor_get_debug_name (self),
1378                        _clutter_actor_get_debug_name (priv->parent));
1379         }
1380
1381       /* If in reparent, we temporarily suspend unmap and unrealize.
1382        *
1383        * We want to go in the order "realize, map" and "unmap, unrealize"
1384        */
1385
1386       /* Unmap */
1387       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1388         clutter_actor_set_mapped (self, FALSE);
1389
1390       /* Realize */
1391       if (must_be_realized)
1392         clutter_actor_realize (self);
1393
1394       /* if we must be realized then we may be, presumably */
1395       g_assert (!(must_be_realized && !may_be_realized));
1396
1397       /* Unrealize */
1398       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1399         clutter_actor_unrealize_not_hiding (self);
1400
1401       /* Map */
1402       if (should_be_mapped)
1403         {
1404           if (!must_be_realized)
1405             g_warning ("Somehow we think actor '%s' should be mapped but "
1406                        "not realized, which isn't allowed",
1407                        _clutter_actor_get_debug_name (self));
1408
1409           /* realization is allowed to fail (though I don't know what
1410            * an app is supposed to do about that - shouldn't it just
1411            * be a g_error? anyway, we have to avoid mapping if this
1412            * happens)
1413            */
1414           if (CLUTTER_ACTOR_IS_REALIZED (self))
1415             clutter_actor_set_mapped (self, TRUE);
1416         }
1417     }
1418
1419 #ifdef CLUTTER_ENABLE_DEBUG
1420   /* check all invariants were kept */
1421   clutter_actor_verify_map_state (self);
1422 #endif
1423 }
1424
1425 static void
1426 clutter_actor_real_map (ClutterActor *self)
1427 {
1428   ClutterActorPrivate *priv = self->priv;
1429   ClutterActor *stage, *iter;
1430
1431   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1432
1433   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1434                 _clutter_actor_get_debug_name (self));
1435
1436   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1437
1438   stage = _clutter_actor_get_stage_internal (self);
1439   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1440
1441   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1442                 priv->pick_id,
1443                 _clutter_actor_get_debug_name (self));
1444
1445   /* notify on parent mapped before potentially mapping
1446    * children, so apps see a top-down notification.
1447    */
1448   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1449
1450   for (iter = self->priv->first_child;
1451        iter != NULL;
1452        iter = iter->priv->next_sibling)
1453     {
1454       clutter_actor_map (iter);
1455     }
1456 }
1457
1458 /**
1459  * clutter_actor_map:
1460  * @self: A #ClutterActor
1461  *
1462  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1463  * and realizes its children if they are visible. Does nothing if the
1464  * actor is not visible.
1465  *
1466  * Calling this function is strongly disencouraged: the default
1467  * implementation of #ClutterActorClass.map() will map all the children
1468  * of an actor when mapping its parent.
1469  *
1470  * When overriding map, it is mandatory to chain up to the parent
1471  * implementation.
1472  *
1473  * Since: 1.0
1474  */
1475 void
1476 clutter_actor_map (ClutterActor *self)
1477 {
1478   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1479
1480   if (CLUTTER_ACTOR_IS_MAPPED (self))
1481     return;
1482
1483   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1484     return;
1485
1486   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1487 }
1488
1489 static void
1490 clutter_actor_real_unmap (ClutterActor *self)
1491 {
1492   ClutterActorPrivate *priv = self->priv;
1493   ClutterActor *iter;
1494
1495   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1496
1497   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1498                 _clutter_actor_get_debug_name (self));
1499
1500   for (iter = self->priv->first_child;
1501        iter != NULL;
1502        iter = iter->priv->next_sibling)
1503     {
1504       clutter_actor_unmap (iter);
1505     }
1506
1507   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1508
1509   /* clear the contents of the last paint volume, so that hiding + moving +
1510    * showing will not result in the wrong area being repainted
1511    */
1512   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1513   priv->last_paint_volume_valid = TRUE;
1514
1515   /* notify on parent mapped after potentially unmapping
1516    * children, so apps see a bottom-up notification.
1517    */
1518   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1519
1520   /* relinquish keyboard focus if we were unmapped while owning it */
1521   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1522     {
1523       ClutterStage *stage;
1524
1525       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1526
1527       if (stage != NULL)
1528         _clutter_stage_release_pick_id (stage, priv->pick_id);
1529
1530       priv->pick_id = -1;
1531
1532       if (stage != NULL &&
1533           clutter_stage_get_key_focus (stage) == self)
1534         {
1535           clutter_stage_set_key_focus (stage, NULL);
1536         }
1537     }
1538 }
1539
1540 /**
1541  * clutter_actor_unmap:
1542  * @self: A #ClutterActor
1543  *
1544  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1545  * unmaps its children if they were mapped.
1546  *
1547  * Calling this function is not encouraged: the default #ClutterActor
1548  * implementation of #ClutterActorClass.unmap() will also unmap any
1549  * eventual children by default when their parent is unmapped.
1550  *
1551  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1552  * chain up to the parent implementation.
1553  *
1554  * <note>It is important to note that the implementation of the
1555  * #ClutterActorClass.unmap() virtual function may be called after
1556  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1557  * implementation, but it is guaranteed to be called before the
1558  * #GObjectClass.finalize() implementation.</note>
1559  *
1560  * Since: 1.0
1561  */
1562 void
1563 clutter_actor_unmap (ClutterActor *self)
1564 {
1565   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1566
1567   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1568     return;
1569
1570   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1571 }
1572
1573 static void
1574 clutter_actor_real_show (ClutterActor *self)
1575 {
1576   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1577     {
1578       ClutterActorPrivate *priv = self->priv;
1579
1580       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1581
1582       /* we notify on the "visible" flag in the clutter_actor_show()
1583        * wrapper so the entire show signal emission completes first
1584        * (?)
1585        */
1586       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1587
1588       /* we queue a relayout unless the actor is inside a
1589        * container that explicitly told us not to
1590        */
1591       if (priv->parent != NULL &&
1592           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1593         {
1594           /* While an actor is hidden the parent may not have
1595            * allocated/requested so we need to start from scratch
1596            * and avoid the short-circuiting in
1597            * clutter_actor_queue_relayout().
1598            */
1599           priv->needs_width_request  = FALSE;
1600           priv->needs_height_request = FALSE;
1601           priv->needs_allocation     = FALSE;
1602           clutter_actor_queue_relayout (self);
1603         }
1604     }
1605 }
1606
1607 static inline void
1608 set_show_on_set_parent (ClutterActor *self,
1609                         gboolean      set_show)
1610 {
1611   ClutterActorPrivate *priv = self->priv;
1612
1613   set_show = !!set_show;
1614
1615   if (priv->show_on_set_parent == set_show)
1616     return;
1617
1618   if (priv->parent == NULL)
1619     {
1620       priv->show_on_set_parent = set_show;
1621       g_object_notify_by_pspec (G_OBJECT (self),
1622                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1623     }
1624 }
1625
1626 /**
1627  * clutter_actor_show:
1628  * @self: A #ClutterActor
1629  *
1630  * Flags an actor to be displayed. An actor that isn't shown will not
1631  * be rendered on the stage.
1632  *
1633  * Actors are visible by default.
1634  *
1635  * If this function is called on an actor without a parent, the
1636  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1637  * effect.
1638  */
1639 void
1640 clutter_actor_show (ClutterActor *self)
1641 {
1642   ClutterActorPrivate *priv;
1643
1644   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1645
1646   /* simple optimization */
1647   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1648     {
1649       /* we still need to set the :show-on-set-parent property, in
1650        * case show() is called on an unparented actor
1651        */
1652       set_show_on_set_parent (self, TRUE);
1653       return;
1654     }
1655
1656 #ifdef CLUTTER_ENABLE_DEBUG
1657   clutter_actor_verify_map_state (self);
1658 #endif
1659
1660   priv = self->priv;
1661
1662   g_object_freeze_notify (G_OBJECT (self));
1663
1664   set_show_on_set_parent (self, TRUE);
1665
1666   /* if we're showing a child that needs to expand, or may
1667    * expand, then we need to recompute the expand flags for
1668    * its parent as well
1669    */
1670   if (priv->needs_compute_expand ||
1671       priv->needs_x_expand ||
1672       priv->needs_y_expand)
1673     {
1674       clutter_actor_queue_compute_expand (self);
1675     }
1676
1677   g_signal_emit (self, actor_signals[SHOW], 0);
1678   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1679
1680   if (priv->parent != NULL)
1681     clutter_actor_queue_redraw (priv->parent);
1682
1683   g_object_thaw_notify (G_OBJECT (self));
1684 }
1685
1686 /**
1687  * clutter_actor_show_all:
1688  * @self: a #ClutterActor
1689  *
1690  * Calls clutter_actor_show() on all children of an actor (if any).
1691  *
1692  * Since: 0.2
1693  *
1694  * Deprecated: 1.10: Actors are visible by default
1695  */
1696 void
1697 clutter_actor_show_all (ClutterActor *self)
1698 {
1699   ClutterActorClass *klass;
1700
1701   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1702
1703   klass = CLUTTER_ACTOR_GET_CLASS (self);
1704   if (klass->show_all)
1705     klass->show_all (self);
1706 }
1707
1708 static void
1709 clutter_actor_real_hide (ClutterActor *self)
1710 {
1711   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1712     {
1713       ClutterActorPrivate *priv = self->priv;
1714
1715       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1716
1717       /* we notify on the "visible" flag in the clutter_actor_hide()
1718        * wrapper so the entire hide signal emission completes first
1719        * (?)
1720        */
1721       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1722
1723       /* we queue a relayout unless the actor is inside a
1724        * container that explicitly told us not to
1725        */
1726       if (priv->parent != NULL &&
1727           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1728         clutter_actor_queue_relayout (priv->parent);
1729     }
1730 }
1731
1732 /**
1733  * clutter_actor_hide:
1734  * @self: A #ClutterActor
1735  *
1736  * Flags an actor to be hidden. A hidden actor will not be
1737  * rendered on the stage.
1738  *
1739  * Actors are visible by default.
1740  *
1741  * If this function is called on an actor without a parent, the
1742  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1743  * as a side-effect.
1744  */
1745 void
1746 clutter_actor_hide (ClutterActor *self)
1747 {
1748   ClutterActorPrivate *priv;
1749
1750   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1751
1752   /* simple optimization */
1753   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1754     {
1755       /* we still need to set the :show-on-set-parent property, in
1756        * case hide() is called on an unparented actor
1757        */
1758       set_show_on_set_parent (self, FALSE);
1759       return;
1760     }
1761
1762 #ifdef CLUTTER_ENABLE_DEBUG
1763   clutter_actor_verify_map_state (self);
1764 #endif
1765
1766   priv = self->priv;
1767
1768   g_object_freeze_notify (G_OBJECT (self));
1769
1770   set_show_on_set_parent (self, FALSE);
1771
1772   /* if we're hiding a child that needs to expand, or may
1773    * expand, then we need to recompute the expand flags for
1774    * its parent as well
1775    */
1776   if (priv->needs_compute_expand ||
1777       priv->needs_x_expand ||
1778       priv->needs_y_expand)
1779     {
1780       clutter_actor_queue_compute_expand (self);
1781     }
1782
1783   g_signal_emit (self, actor_signals[HIDE], 0);
1784   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1785
1786   if (priv->parent != NULL)
1787     clutter_actor_queue_redraw (priv->parent);
1788
1789   g_object_thaw_notify (G_OBJECT (self));
1790 }
1791
1792 /**
1793  * clutter_actor_hide_all:
1794  * @self: a #ClutterActor
1795  *
1796  * Calls clutter_actor_hide() on all child actors (if any).
1797  *
1798  * Since: 0.2
1799  *
1800  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1801  *   prevent its children from being painted as well.
1802  */
1803 void
1804 clutter_actor_hide_all (ClutterActor *self)
1805 {
1806   ClutterActorClass *klass;
1807
1808   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1809
1810   klass = CLUTTER_ACTOR_GET_CLASS (self);
1811   if (klass->hide_all)
1812     klass->hide_all (self);
1813 }
1814
1815 /**
1816  * clutter_actor_realize:
1817  * @self: A #ClutterActor
1818  *
1819  * Realization informs the actor that it is attached to a stage. It
1820  * can use this to allocate resources if it wanted to delay allocation
1821  * until it would be rendered. However it is perfectly acceptable for
1822  * an actor to create resources before being realized because Clutter
1823  * only ever has a single rendering context so that actor is free to
1824  * be moved from one stage to another.
1825  *
1826  * This function does nothing if the actor is already realized.
1827  *
1828  * Because a realized actor must have realized parent actors, calling
1829  * clutter_actor_realize() will also realize all parents of the actor.
1830  *
1831  * This function does not realize child actors, except in the special
1832  * case that realizing the stage, when the stage is visible, will
1833  * suddenly map (and thus realize) the children of the stage.
1834  **/
1835 void
1836 clutter_actor_realize (ClutterActor *self)
1837 {
1838   ClutterActorPrivate *priv;
1839
1840   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1841
1842   priv = self->priv;
1843
1844 #ifdef CLUTTER_ENABLE_DEBUG
1845   clutter_actor_verify_map_state (self);
1846 #endif
1847
1848   if (CLUTTER_ACTOR_IS_REALIZED (self))
1849     return;
1850
1851   /* To be realized, our parent actors must be realized first.
1852    * This will only succeed if we're inside a toplevel.
1853    */
1854   if (priv->parent != NULL)
1855     clutter_actor_realize (priv->parent);
1856
1857   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1858     {
1859       /* toplevels can be realized at any time */
1860     }
1861   else
1862     {
1863       /* "Fail" the realization if parent is missing or unrealized;
1864        * this should really be a g_warning() not some kind of runtime
1865        * failure; how can an app possibly recover? Instead it's a bug
1866        * in the app and the app should get an explanatory warning so
1867        * someone can fix it. But for now it's too hard to fix this
1868        * because e.g. ClutterTexture needs reworking.
1869        */
1870       if (priv->parent == NULL ||
1871           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1872         return;
1873     }
1874
1875   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1876
1877   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1878   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1879
1880   g_signal_emit (self, actor_signals[REALIZE], 0);
1881
1882   /* Stage actor is allowed to unset the realized flag again in its
1883    * default signal handler, though that is a pathological situation.
1884    */
1885
1886   /* If realization "failed" we'll have to update child state. */
1887   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1888 }
1889
1890 static void
1891 clutter_actor_real_unrealize (ClutterActor *self)
1892 {
1893   /* we must be unmapped (implying our children are also unmapped) */
1894   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1895 }
1896
1897 /**
1898  * clutter_actor_unrealize:
1899  * @self: A #ClutterActor
1900  *
1901  * Unrealization informs the actor that it may be being destroyed or
1902  * moved to another stage. The actor may want to destroy any
1903  * underlying graphics resources at this point. However it is
1904  * perfectly acceptable for it to retain the resources until the actor
1905  * is destroyed because Clutter only ever uses a single rendering
1906  * context and all of the graphics resources are valid on any stage.
1907  *
1908  * Because mapped actors must be realized, actors may not be
1909  * unrealized if they are mapped. This function hides the actor to be
1910  * sure it isn't mapped, an application-visible side effect that you
1911  * may not be expecting.
1912  *
1913  * This function should not be called by application code.
1914  */
1915 void
1916 clutter_actor_unrealize (ClutterActor *self)
1917 {
1918   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1919   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1920
1921 /* This function should not really be in the public API, because
1922  * there isn't a good reason to call it. ClutterActor will already
1923  * unrealize things for you when it's important to do so.
1924  *
1925  * If you were using clutter_actor_unrealize() in a dispose
1926  * implementation, then don't, just chain up to ClutterActor's
1927  * dispose.
1928  *
1929  * If you were using clutter_actor_unrealize() to implement
1930  * unrealizing children of your container, then don't, ClutterActor
1931  * will already take care of that.
1932  *
1933  * If you were using clutter_actor_unrealize() to re-realize to
1934  * create your resources in a different way, then use
1935  * _clutter_actor_rerealize() (inside Clutter) or just call your
1936  * code that recreates your resources directly (outside Clutter).
1937  */
1938
1939 #ifdef CLUTTER_ENABLE_DEBUG
1940   clutter_actor_verify_map_state (self);
1941 #endif
1942
1943   clutter_actor_hide (self);
1944
1945   clutter_actor_unrealize_not_hiding (self);
1946 }
1947
1948 static ClutterActorTraverseVisitFlags
1949 unrealize_actor_before_children_cb (ClutterActor *self,
1950                                     int depth,
1951                                     void *user_data)
1952 {
1953   /* If an actor is already unrealized we know its children have also
1954    * already been unrealized... */
1955   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1956     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1957
1958   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1959
1960   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1961 }
1962
1963 static ClutterActorTraverseVisitFlags
1964 unrealize_actor_after_children_cb (ClutterActor *self,
1965                                    int depth,
1966                                    void *user_data)
1967 {
1968   /* We want to unset the realized flag only _after_
1969    * child actors are unrealized, to maintain invariants.
1970    */
1971   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1972   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1973   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1974 }
1975
1976 /*
1977  * clutter_actor_unrealize_not_hiding:
1978  * @self: A #ClutterActor
1979  *
1980  * Unrealization informs the actor that it may be being destroyed or
1981  * moved to another stage. The actor may want to destroy any
1982  * underlying graphics resources at this point. However it is
1983  * perfectly acceptable for it to retain the resources until the actor
1984  * is destroyed because Clutter only ever uses a single rendering
1985  * context and all of the graphics resources are valid on any stage.
1986  *
1987  * Because mapped actors must be realized, actors may not be
1988  * unrealized if they are mapped. You must hide the actor or one of
1989  * its parents before attempting to unrealize.
1990  *
1991  * This function is separate from clutter_actor_unrealize() because it
1992  * does not automatically hide the actor.
1993  * Actors need not be hidden to be unrealized, they just need to
1994  * be unmapped. In fact we don't want to mess up the application's
1995  * setting of the "visible" flag, so hiding is very undesirable.
1996  *
1997  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1998  * backward compatibility.
1999  */
2000 static void
2001 clutter_actor_unrealize_not_hiding (ClutterActor *self)
2002 {
2003   _clutter_actor_traverse (self,
2004                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
2005                            unrealize_actor_before_children_cb,
2006                            unrealize_actor_after_children_cb,
2007                            NULL);
2008 }
2009
2010 /*
2011  * _clutter_actor_rerealize:
2012  * @self: A #ClutterActor
2013  * @callback: Function to call while unrealized
2014  * @data: data for callback
2015  *
2016  * If an actor is already unrealized, this just calls the callback.
2017  *
2018  * If it is realized, it unrealizes temporarily, calls the callback,
2019  * and then re-realizes the actor.
2020  *
2021  * As a side effect, leaves all children of the actor unrealized if
2022  * the actor was realized but not showing.  This is because when we
2023  * unrealize the actor temporarily we must unrealize its children
2024  * (e.g. children of a stage can't be realized if stage window is
2025  * gone). And we aren't clever enough to save the realization state of
2026  * all children. In most cases this should not matter, because
2027  * the children will automatically realize when they next become mapped.
2028  */
2029 void
2030 _clutter_actor_rerealize (ClutterActor    *self,
2031                           ClutterCallback  callback,
2032                           void            *data)
2033 {
2034   gboolean was_mapped;
2035   gboolean was_showing;
2036   gboolean was_realized;
2037
2038   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2039
2040 #ifdef CLUTTER_ENABLE_DEBUG
2041   clutter_actor_verify_map_state (self);
2042 #endif
2043
2044   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
2045   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
2046   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
2047
2048   /* Must be unmapped to unrealize. Note we only have to hide this
2049    * actor if it was mapped (if all parents were showing).  If actor
2050    * is merely visible (but not mapped), then that's fine, we can
2051    * leave it visible.
2052    */
2053   if (was_mapped)
2054     clutter_actor_hide (self);
2055
2056   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
2057
2058   /* unrealize self and all children */
2059   clutter_actor_unrealize_not_hiding (self);
2060
2061   if (callback != NULL)
2062     {
2063       (* callback) (self, data);
2064     }
2065
2066   if (was_showing)
2067     clutter_actor_show (self); /* will realize only if mapping implies it */
2068   else if (was_realized)
2069     clutter_actor_realize (self); /* realize self and all parents */
2070 }
2071
2072 static void
2073 clutter_actor_real_pick (ClutterActor       *self,
2074                          const ClutterColor *color)
2075 {
2076   /* the default implementation is just to paint a rectangle
2077    * with the same size of the actor using the passed color
2078    */
2079   if (clutter_actor_should_pick_paint (self))
2080     {
2081       ClutterActorBox box = { 0, };
2082       float width, height;
2083
2084       clutter_actor_get_allocation_box (self, &box);
2085
2086       width = box.x2 - box.x1;
2087       height = box.y2 - box.y1;
2088
2089       cogl_set_source_color4ub (color->red,
2090                                 color->green,
2091                                 color->blue,
2092                                 color->alpha);
2093
2094       cogl_rectangle (0, 0, width, height);
2095     }
2096
2097   /* XXX - this thoroughly sucks, but we need to maintain compatibility
2098    * with existing container classes that override the pick() virtual
2099    * and chain up to the default implementation - otherwise we'll end up
2100    * painting our children twice.
2101    *
2102    * this has to go away for 2.0; hopefully along the pick() itself.
2103    */
2104   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2105     {
2106       ClutterActor *iter;
2107
2108       for (iter = self->priv->first_child;
2109            iter != NULL;
2110            iter = iter->priv->next_sibling)
2111         clutter_actor_paint (iter);
2112     }
2113 }
2114
2115 /**
2116  * clutter_actor_should_pick_paint:
2117  * @self: A #ClutterActor
2118  *
2119  * Should be called inside the implementation of the
2120  * #ClutterActor::pick virtual function in order to check whether
2121  * the actor should paint itself in pick mode or not.
2122  *
2123  * This function should never be called directly by applications.
2124  *
2125  * Return value: %TRUE if the actor should paint its silhouette,
2126  *   %FALSE otherwise
2127  */
2128 gboolean
2129 clutter_actor_should_pick_paint (ClutterActor *self)
2130 {
2131   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2132
2133   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2134       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2135        CLUTTER_ACTOR_IS_REACTIVE (self)))
2136     return TRUE;
2137
2138   return FALSE;
2139 }
2140
2141 static void
2142 clutter_actor_real_get_preferred_width (ClutterActor *self,
2143                                         gfloat        for_height,
2144                                         gfloat       *min_width_p,
2145                                         gfloat       *natural_width_p)
2146 {
2147   ClutterActorPrivate *priv = self->priv;
2148
2149   if (priv->n_children != 0 &&
2150       priv->layout_manager != NULL)
2151     {
2152       ClutterContainer *container = CLUTTER_CONTAINER (self);
2153
2154       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2155                     "for the preferred width",
2156                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2157                     priv->layout_manager);
2158
2159       clutter_layout_manager_get_preferred_width (priv->layout_manager,
2160                                                   container,
2161                                                   for_height,
2162                                                   min_width_p,
2163                                                   natural_width_p);
2164
2165       return;
2166     }
2167
2168   /* Default implementation is always 0x0, usually an actor
2169    * using this default is relying on someone to set the
2170    * request manually
2171    */
2172   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2173
2174   if (min_width_p)
2175     *min_width_p = 0;
2176
2177   if (natural_width_p)
2178     *natural_width_p = 0;
2179 }
2180
2181 static void
2182 clutter_actor_real_get_preferred_height (ClutterActor *self,
2183                                          gfloat        for_width,
2184                                          gfloat       *min_height_p,
2185                                          gfloat       *natural_height_p)
2186 {
2187   ClutterActorPrivate *priv = self->priv;
2188
2189   if (priv->n_children != 0 &&
2190       priv->layout_manager != NULL)
2191     {
2192       ClutterContainer *container = CLUTTER_CONTAINER (self);
2193
2194       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2195                     "for the preferred height",
2196                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2197                     priv->layout_manager);
2198
2199       clutter_layout_manager_get_preferred_height (priv->layout_manager,
2200                                                    container,
2201                                                    for_width,
2202                                                    min_height_p,
2203                                                    natural_height_p);
2204
2205       return;
2206     }
2207   /* Default implementation is always 0x0, usually an actor
2208    * using this default is relying on someone to set the
2209    * request manually
2210    */
2211   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2212
2213   if (min_height_p)
2214     *min_height_p = 0;
2215
2216   if (natural_height_p)
2217     *natural_height_p = 0;
2218 }
2219
2220 static void
2221 clutter_actor_store_old_geometry (ClutterActor    *self,
2222                                   ClutterActorBox *box)
2223 {
2224   *box = self->priv->allocation;
2225 }
2226
2227 static inline void
2228 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2229                                           const ClutterActorBox *old)
2230 {
2231   ClutterActorPrivate *priv = self->priv;
2232   GObject *obj = G_OBJECT (self);
2233
2234   g_object_freeze_notify (obj);
2235
2236   /* to avoid excessive requisition or allocation cycles we
2237    * use the cached values.
2238    *
2239    * - if we don't have an allocation we assume that we need
2240    *   to notify anyway
2241    * - if we don't have a width or a height request we notify
2242    *   width and height
2243    * - if we have a valid allocation then we check the old
2244    *   bounding box with the current allocation and we notify
2245    *   the changes
2246    */
2247   if (priv->needs_allocation)
2248     {
2249       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2250       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2251       g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2252       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2253       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2254       g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2255     }
2256   else if (priv->needs_width_request || priv->needs_height_request)
2257     {
2258       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2259       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2260       g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2261     }
2262   else
2263     {
2264       gfloat x, y;
2265       gfloat width, height;
2266
2267       x = priv->allocation.x1;
2268       y = priv->allocation.y1;
2269       width = priv->allocation.x2 - priv->allocation.x1;
2270       height = priv->allocation.y2 - priv->allocation.y1;
2271
2272       if (x != old->x1)
2273         {
2274           g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2275           g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2276         }
2277
2278       if (y != old->y1)
2279         {
2280           g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2281           g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2282         }
2283
2284       if (width != (old->x2 - old->x1))
2285         {
2286           g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2287           g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2288         }
2289
2290       if (height != (old->y2 - old->y1))
2291         {
2292           g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2293           g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2294         }
2295     }
2296
2297   g_object_thaw_notify (obj);
2298 }
2299
2300 /*< private >
2301  * clutter_actor_set_allocation_internal:
2302  * @self: a #ClutterActor
2303  * @box: a #ClutterActorBox
2304  * @flags: allocation flags
2305  *
2306  * Stores the allocation of @self.
2307  *
2308  * This function only performs basic storage and property notification.
2309  *
2310  * This function should be called by clutter_actor_set_allocation()
2311  * and by the default implementation of #ClutterActorClass.allocate().
2312  *
2313  * Return value: %TRUE if the allocation of the #ClutterActor has been
2314  *   changed, and %FALSE otherwise
2315  */
2316 static inline gboolean
2317 clutter_actor_set_allocation_internal (ClutterActor           *self,
2318                                        const ClutterActorBox  *box,
2319                                        ClutterAllocationFlags  flags)
2320 {
2321   ClutterActorPrivate *priv = self->priv;
2322   GObject *obj;
2323   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2324   gboolean retval;
2325   ClutterActorBox old_alloc = { 0, };
2326
2327   obj = G_OBJECT (self);
2328
2329   g_object_freeze_notify (obj);
2330
2331   clutter_actor_store_old_geometry (self, &old_alloc);
2332
2333   x1_changed = priv->allocation.x1 != box->x1;
2334   y1_changed = priv->allocation.y1 != box->y1;
2335   x2_changed = priv->allocation.x2 != box->x2;
2336   y2_changed = priv->allocation.y2 != box->y2;
2337
2338   priv->allocation = *box;
2339   priv->allocation_flags = flags;
2340
2341   /* allocation is authoritative */
2342   priv->needs_width_request = FALSE;
2343   priv->needs_height_request = FALSE;
2344   priv->needs_allocation = FALSE;
2345
2346   if (x1_changed ||
2347       y1_changed ||
2348       x2_changed ||
2349       y2_changed)
2350     {
2351       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2352                     _clutter_actor_get_debug_name (self));
2353
2354       priv->transform_valid = FALSE;
2355
2356       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2357
2358       /* if the allocation changes, so does the content box */
2359       if (priv->content != NULL)
2360         {
2361           priv->content_box_valid = FALSE;
2362           g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2363         }
2364
2365       retval = TRUE;
2366     }
2367   else
2368     retval = FALSE;
2369
2370   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2371
2372   g_object_thaw_notify (obj);
2373
2374   return retval;
2375 }
2376
2377 static void clutter_actor_real_allocate (ClutterActor           *self,
2378                                          const ClutterActorBox  *box,
2379                                          ClutterAllocationFlags  flags);
2380
2381 static inline void
2382 clutter_actor_maybe_layout_children (ClutterActor           *self,
2383                                      const ClutterActorBox  *allocation,
2384                                      ClutterAllocationFlags  flags)
2385 {
2386   ClutterActorPrivate *priv = self->priv;
2387
2388   /* this is going to be a bit hard to follow, so let's put an explanation
2389    * here.
2390    *
2391    * we want ClutterActor to have a default layout manager if the actor was
2392    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2393    *
2394    * we also want any subclass of ClutterActor that does not override the
2395    * ::allocate() virtual function to delegate to a layout manager.
2396    *
2397    * finally, we want to allow people subclassing ClutterActor and overriding
2398    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2399    *
2400    * on the other hand, we want existing actor subclasses overriding the
2401    * ::allocate() virtual function and chaining up to the parent's
2402    * implementation to continue working without allocating their children
2403    * twice, or without entering an allocation loop.
2404    *
2405    * for the first two points, we check if the class of the actor is
2406    * overridding the ::allocate() virtual function; if it isn't, then we
2407    * follow through with checking whether we have children and a layout
2408    * manager, and eventually calling clutter_layout_manager_allocate().
2409    *
2410    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2411    * allocation flags that we got passed, and if it is present, we continue
2412    * with the check above.
2413    *
2414    * if neither of these two checks yields a positive result, we just
2415    * assume that the ::allocate() virtual function that resulted in this
2416    * function being called will also allocate the children of the actor.
2417    */
2418
2419   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2420     goto check_layout;
2421
2422   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2423     goto check_layout;
2424
2425   return;
2426
2427 check_layout:
2428   if (priv->n_children != 0 &&
2429       priv->layout_manager != NULL)
2430     {
2431       ClutterContainer *container = CLUTTER_CONTAINER (self);
2432       ClutterAllocationFlags children_flags;
2433       ClutterActorBox children_box;
2434
2435       /* normalize the box passed to the layout manager */
2436       children_box.x1 = children_box.y1 = 0.f;
2437       children_box.x2 = (allocation->x2 - allocation->x1);
2438       children_box.y2 = (allocation->y2 - allocation->y1);
2439
2440       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2441        * the actor's children, since it refers only to the current
2442        * actor's allocation.
2443        */
2444       children_flags = flags;
2445       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2446
2447       CLUTTER_NOTE (LAYOUT,
2448                     "Allocating %d children of %s "
2449                     "at { %.2f, %.2f - %.2f x %.2f } "
2450                     "using %s",
2451                     priv->n_children,
2452                     _clutter_actor_get_debug_name (self),
2453                     allocation->x1,
2454                     allocation->y1,
2455                     (allocation->x2 - allocation->x1),
2456                     (allocation->y2 - allocation->y1),
2457                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2458
2459       clutter_layout_manager_allocate (priv->layout_manager,
2460                                        container,
2461                                        &children_box,
2462                                        children_flags);
2463     }
2464 }
2465
2466 static void
2467 clutter_actor_real_allocate (ClutterActor           *self,
2468                              const ClutterActorBox  *box,
2469                              ClutterAllocationFlags  flags)
2470 {
2471   ClutterActorPrivate *priv = self->priv;
2472   gboolean changed;
2473
2474   g_object_freeze_notify (G_OBJECT (self));
2475
2476   changed = clutter_actor_set_allocation_internal (self, box, flags);
2477
2478   /* we allocate our children before we notify changes in our geometry,
2479    * so that people connecting to properties will be able to get valid
2480    * data out of the sub-tree of the scene graph that has this actor at
2481    * the root.
2482    */
2483   clutter_actor_maybe_layout_children (self, box, flags);
2484
2485   if (changed)
2486     {
2487       ClutterActorBox signal_box = priv->allocation;
2488       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2489
2490       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2491                      &signal_box,
2492                      signal_flags);
2493     }
2494
2495   g_object_thaw_notify (G_OBJECT (self));
2496 }
2497
2498 static void
2499 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2500                                     ClutterActor *origin)
2501 {
2502   /* no point in queuing a redraw on a destroyed actor */
2503   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2504     return;
2505
2506   /* NB: We can't bail out early here if the actor is hidden in case
2507    * the actor bas been cloned. In this case the clone will need to
2508    * receive the signal so it can queue its own redraw.
2509    */
2510
2511   /* calls klass->queue_redraw in default handler */
2512   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2513 }
2514
2515 static void
2516 clutter_actor_real_queue_redraw (ClutterActor *self,
2517                                  ClutterActor *origin)
2518 {
2519   ClutterActor *parent;
2520
2521   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2522                 _clutter_actor_get_debug_name (self),
2523                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2524                                : "same actor");
2525
2526   /* no point in queuing a redraw on a destroyed actor */
2527   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2528     return;
2529
2530   /* If the queue redraw is coming from a child then the actor has
2531      become dirty and any queued effect is no longer valid */
2532   if (self != origin)
2533     {
2534       self->priv->is_dirty = TRUE;
2535       self->priv->effect_to_redraw = NULL;
2536     }
2537
2538   /* If the actor isn't visible, we still had to emit the signal
2539    * to allow for a ClutterClone, but the appearance of the parent
2540    * won't change so we don't have to propagate up the hierarchy.
2541    */
2542   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2543     return;
2544
2545   /* Although we could determine here that a full stage redraw
2546    * has already been queued and immediately bail out, we actually
2547    * guarantee that we will propagate a queue-redraw signal to our
2548    * parent at least once so that it's possible to implement a
2549    * container that tracks which of its children have queued a
2550    * redraw.
2551    */
2552   if (self->priv->propagated_one_redraw)
2553     {
2554       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2555       if (stage != NULL &&
2556           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2557         return;
2558     }
2559
2560   self->priv->propagated_one_redraw = TRUE;
2561
2562   /* notify parents, if they are all visible eventually we'll
2563    * queue redraw on the stage, which queues the redraw idle.
2564    */
2565   parent = clutter_actor_get_parent (self);
2566   if (parent != NULL)
2567     {
2568       /* this will go up recursively */
2569       _clutter_actor_signal_queue_redraw (parent, origin);
2570     }
2571 }
2572
2573 static void
2574 clutter_actor_real_queue_relayout (ClutterActor *self)
2575 {
2576   ClutterActorPrivate *priv = self->priv;
2577
2578   /* no point in queueing a redraw on a destroyed actor */
2579   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2580     return;
2581
2582   priv->needs_width_request  = TRUE;
2583   priv->needs_height_request = TRUE;
2584   priv->needs_allocation     = TRUE;
2585
2586   /* reset the cached size requests */
2587   memset (priv->width_requests, 0,
2588           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2589   memset (priv->height_requests, 0,
2590           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2591
2592   /* We need to go all the way up the hierarchy */
2593   if (priv->parent != NULL)
2594     _clutter_actor_queue_only_relayout (priv->parent);
2595 }
2596
2597 /**
2598  * clutter_actor_apply_relative_transform_to_point:
2599  * @self: A #ClutterActor
2600  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2601  *   default #ClutterStage
2602  * @point: A point as #ClutterVertex
2603  * @vertex: (out caller-allocates): The translated #ClutterVertex
2604  *
2605  * Transforms @point in coordinates relative to the actor into
2606  * ancestor-relative coordinates using the relevant transform
2607  * stack (i.e. scale, rotation, etc).
2608  *
2609  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2610  * this case, the coordinates returned will be the coordinates on
2611  * the stage before the projection is applied. This is different from
2612  * the behaviour of clutter_actor_apply_transform_to_point().
2613  *
2614  * Since: 0.6
2615  */
2616 void
2617 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2618                                                  ClutterActor        *ancestor,
2619                                                  const ClutterVertex *point,
2620                                                  ClutterVertex       *vertex)
2621 {
2622   gfloat w;
2623   CoglMatrix matrix;
2624
2625   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2626   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2627   g_return_if_fail (point != NULL);
2628   g_return_if_fail (vertex != NULL);
2629
2630   *vertex = *point;
2631   w = 1.0;
2632
2633   if (ancestor == NULL)
2634     ancestor = _clutter_actor_get_stage_internal (self);
2635
2636   if (ancestor == NULL)
2637     {
2638       *vertex = *point;
2639       return;
2640     }
2641
2642   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2643   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2644 }
2645
2646 static gboolean
2647 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2648                                          const ClutterVertex *vertices_in,
2649                                          ClutterVertex *vertices_out,
2650                                          int n_vertices)
2651 {
2652   ClutterActor *stage;
2653   CoglMatrix modelview;
2654   CoglMatrix projection;
2655   float viewport[4];
2656
2657   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2658
2659   stage = _clutter_actor_get_stage_internal (self);
2660
2661   /* We really can't do anything meaningful in this case so don't try
2662    * to do any transform */
2663   if (stage == NULL)
2664     return FALSE;
2665
2666   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2667    * that gets us to stage coordinates, we want to go all the way to eye
2668    * coordinates */
2669   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2670
2671   /* Fetch the projection and viewport */
2672   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2673   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2674                                &viewport[0],
2675                                &viewport[1],
2676                                &viewport[2],
2677                                &viewport[3]);
2678
2679   _clutter_util_fully_transform_vertices (&modelview,
2680                                           &projection,
2681                                           viewport,
2682                                           vertices_in,
2683                                           vertices_out,
2684                                           n_vertices);
2685
2686   return TRUE;
2687 }
2688
2689 /**
2690  * clutter_actor_apply_transform_to_point:
2691  * @self: A #ClutterActor
2692  * @point: A point as #ClutterVertex
2693  * @vertex: (out caller-allocates): The translated #ClutterVertex
2694  *
2695  * Transforms @point in coordinates relative to the actor
2696  * into screen-relative coordinates with the current actor
2697  * transformation (i.e. scale, rotation, etc)
2698  *
2699  * Since: 0.4
2700  **/
2701 void
2702 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2703                                         const ClutterVertex *point,
2704                                         ClutterVertex       *vertex)
2705 {
2706   g_return_if_fail (point != NULL);
2707   g_return_if_fail (vertex != NULL);
2708   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2709 }
2710
2711 /*
2712  * _clutter_actor_get_relative_transformation_matrix:
2713  * @self: The actor whose coordinate space you want to transform from.
2714  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2715  *            or %NULL if you want to transform all the way to eye coordinates.
2716  * @matrix: A #CoglMatrix to store the transformation
2717  *
2718  * This gets a transformation @matrix that will transform coordinates from the
2719  * coordinate space of @self into the coordinate space of @ancestor.
2720  *
2721  * For example if you need a matrix that can transform the local actor
2722  * coordinates of @self into stage coordinates you would pass the actor's stage
2723  * pointer as the @ancestor.
2724  *
2725  * If you pass %NULL then the transformation will take you all the way through
2726  * to eye coordinates. This can be useful if you want to extract the entire
2727  * modelview transform that Clutter applies before applying the projection
2728  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2729  * using cogl_set_modelview_matrix() for example then you would want a matrix
2730  * that transforms into eye coordinates.
2731  *
2732  * <note><para>This function explicitly initializes the given @matrix. If you just
2733  * want clutter to multiply a relative transformation with an existing matrix
2734  * you can use clutter_actor_apply_relative_transformation_matrix()
2735  * instead.</para></note>
2736  *
2737  */
2738 /* XXX: We should consider caching the stage relative modelview along with
2739  * the actor itself */
2740 static void
2741 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2742                                                    ClutterActor *ancestor,
2743                                                    CoglMatrix *matrix)
2744 {
2745   cogl_matrix_init_identity (matrix);
2746
2747   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2748 }
2749
2750 /* Project the given @box into stage window coordinates, writing the
2751  * transformed vertices to @verts[]. */
2752 static gboolean
2753 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2754                                           const ClutterActorBox *box,
2755                                           ClutterVertex          verts[])
2756 {
2757   ClutterVertex box_vertices[4];
2758
2759   box_vertices[0].x = box->x1;
2760   box_vertices[0].y = box->y1;
2761   box_vertices[0].z = 0;
2762   box_vertices[1].x = box->x2;
2763   box_vertices[1].y = box->y1;
2764   box_vertices[1].z = 0;
2765   box_vertices[2].x = box->x1;
2766   box_vertices[2].y = box->y2;
2767   box_vertices[2].z = 0;
2768   box_vertices[3].x = box->x2;
2769   box_vertices[3].y = box->y2;
2770   box_vertices[3].z = 0;
2771
2772   return
2773     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2774 }
2775
2776 /**
2777  * clutter_actor_get_allocation_vertices:
2778  * @self: A #ClutterActor
2779  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2780  *   against, or %NULL to use the #ClutterStage
2781  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2782  *   location for an array of 4 #ClutterVertex in which to store the result
2783  *
2784  * Calculates the transformed coordinates of the four corners of the
2785  * actor in the plane of @ancestor. The returned vertices relate to
2786  * the #ClutterActorBox coordinates as follows:
2787  * <itemizedlist>
2788  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2789  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2790  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2791  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2792  * </itemizedlist>
2793  *
2794  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2795  * this case, the coordinates returned will be the coordinates on
2796  * the stage before the projection is applied. This is different from
2797  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2798  *
2799  * Since: 0.6
2800  */
2801 void
2802 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2803                                        ClutterActor  *ancestor,
2804                                        ClutterVertex  verts[])
2805 {
2806   ClutterActorPrivate *priv;
2807   ClutterActorBox box;
2808   ClutterVertex vertices[4];
2809   CoglMatrix modelview;
2810
2811   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2812   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2813
2814   if (ancestor == NULL)
2815     ancestor = _clutter_actor_get_stage_internal (self);
2816
2817   /* Fallback to a NOP transform if the actor isn't parented under a
2818    * stage. */
2819   if (ancestor == NULL)
2820     ancestor = self;
2821
2822   priv = self->priv;
2823
2824   /* if the actor needs to be allocated we force a relayout, so that
2825    * we will have valid values to use in the transformations */
2826   if (priv->needs_allocation)
2827     {
2828       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2829       if (stage)
2830         _clutter_stage_maybe_relayout (stage);
2831       else
2832         {
2833           box.x1 = box.y1 = 0;
2834           /* The result isn't really meaningful in this case but at
2835            * least try to do something *vaguely* reasonable... */
2836           clutter_actor_get_size (self, &box.x2, &box.y2);
2837         }
2838     }
2839
2840   clutter_actor_get_allocation_box (self, &box);
2841
2842   vertices[0].x = box.x1;
2843   vertices[0].y = box.y1;
2844   vertices[0].z = 0;
2845   vertices[1].x = box.x2;
2846   vertices[1].y = box.y1;
2847   vertices[1].z = 0;
2848   vertices[2].x = box.x1;
2849   vertices[2].y = box.y2;
2850   vertices[2].z = 0;
2851   vertices[3].x = box.x2;
2852   vertices[3].y = box.y2;
2853   vertices[3].z = 0;
2854
2855   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2856                                                      &modelview);
2857
2858   cogl_matrix_transform_points (&modelview,
2859                                 3,
2860                                 sizeof (ClutterVertex),
2861                                 vertices,
2862                                 sizeof (ClutterVertex),
2863                                 vertices,
2864                                 4);
2865 }
2866
2867 /**
2868  * clutter_actor_get_abs_allocation_vertices:
2869  * @self: A #ClutterActor
2870  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2871  *   of 4 #ClutterVertex where to store the result.
2872  *
2873  * Calculates the transformed screen coordinates of the four corners of
2874  * the actor; the returned vertices relate to the #ClutterActorBox
2875  * coordinates  as follows:
2876  * <itemizedlist>
2877  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2878  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2879  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2880  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2881  * </itemizedlist>
2882  *
2883  * Since: 0.4
2884  */
2885 void
2886 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2887                                            ClutterVertex  verts[])
2888 {
2889   ClutterActorPrivate *priv;
2890   ClutterActorBox actor_space_allocation;
2891
2892   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2893
2894   priv = self->priv;
2895
2896   /* if the actor needs to be allocated we force a relayout, so that
2897    * the actor allocation box will be valid for
2898    * _clutter_actor_transform_and_project_box()
2899    */
2900   if (priv->needs_allocation)
2901     {
2902       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2903       /* There's nothing meaningful we can do now */
2904       if (!stage)
2905         return;
2906
2907       _clutter_stage_maybe_relayout (stage);
2908     }
2909
2910   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2911    * own coordinate space... */
2912   actor_space_allocation.x1 = 0;
2913   actor_space_allocation.y1 = 0;
2914   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2915   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2916   _clutter_actor_transform_and_project_box (self,
2917                                             &actor_space_allocation,
2918                                             verts);
2919 }
2920
2921 static void
2922 clutter_actor_real_apply_transform (ClutterActor *self,
2923                                     CoglMatrix   *matrix)
2924 {
2925   ClutterActorPrivate *priv = self->priv;
2926
2927   if (!priv->transform_valid)
2928     {
2929       CoglMatrix *transform = &priv->transform;
2930       const ClutterTransformInfo *info;
2931
2932       info = _clutter_actor_get_transform_info_or_defaults (self);
2933
2934       cogl_matrix_init_identity (transform);
2935
2936       cogl_matrix_translate (transform,
2937                              priv->allocation.x1,
2938                              priv->allocation.y1,
2939                              0.0);
2940
2941       if (info->depth)
2942         cogl_matrix_translate (transform, 0, 0, info->depth);
2943
2944       /*
2945        * because the rotation involves translations, we must scale
2946        * before applying the rotations (if we apply the scale after
2947        * the rotations, the translations included in the rotation are
2948        * not scaled and so the entire object will move on the screen
2949        * as a result of rotating it).
2950        */
2951       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2952         {
2953           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2954                                         &info->scale_center,
2955                                         cogl_matrix_scale (transform,
2956                                                            info->scale_x,
2957                                                            info->scale_y,
2958                                                            1.0));
2959         }
2960
2961       if (info->rz_angle)
2962         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2963                                       &info->rz_center,
2964                                       cogl_matrix_rotate (transform,
2965                                                           info->rz_angle,
2966                                                           0, 0, 1.0));
2967
2968       if (info->ry_angle)
2969         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2970                                       &info->ry_center,
2971                                       cogl_matrix_rotate (transform,
2972                                                           info->ry_angle,
2973                                                           0, 1.0, 0));
2974
2975       if (info->rx_angle)
2976         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2977                                       &info->rx_center,
2978                                       cogl_matrix_rotate (transform,
2979                                                           info->rx_angle,
2980                                                           1.0, 0, 0));
2981
2982       if (!clutter_anchor_coord_is_zero (&info->anchor))
2983         {
2984           gfloat x, y, z;
2985
2986           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2987           cogl_matrix_translate (transform, -x, -y, -z);
2988         }
2989
2990       priv->transform_valid = TRUE;
2991     }
2992
2993   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2994 }
2995
2996 /* Applies the transforms associated with this actor to the given
2997  * matrix. */
2998 void
2999 _clutter_actor_apply_modelview_transform (ClutterActor *self,
3000                                           CoglMatrix *matrix)
3001 {
3002   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
3003 }
3004
3005 /*
3006  * clutter_actor_apply_relative_transformation_matrix:
3007  * @self: The actor whose coordinate space you want to transform from.
3008  * @ancestor: The ancestor actor whose coordinate space you want to transform too
3009  *            or %NULL if you want to transform all the way to eye coordinates.
3010  * @matrix: A #CoglMatrix to apply the transformation too.
3011  *
3012  * This multiplies a transform with @matrix that will transform coordinates
3013  * from the coordinate space of @self into the coordinate space of @ancestor.
3014  *
3015  * For example if you need a matrix that can transform the local actor
3016  * coordinates of @self into stage coordinates you would pass the actor's stage
3017  * pointer as the @ancestor.
3018  *
3019  * If you pass %NULL then the transformation will take you all the way through
3020  * to eye coordinates. This can be useful if you want to extract the entire
3021  * modelview transform that Clutter applies before applying the projection
3022  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
3023  * using cogl_set_modelview_matrix() for example then you would want a matrix
3024  * that transforms into eye coordinates.
3025  *
3026  * <note>This function doesn't initialize the given @matrix, it simply
3027  * multiplies the requested transformation matrix with the existing contents of
3028  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
3029  * before calling this function, or you can use
3030  * clutter_actor_get_relative_transformation_matrix() instead.</note>
3031  */
3032 void
3033 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
3034                                                      ClutterActor *ancestor,
3035                                                      CoglMatrix *matrix)
3036 {
3037   ClutterActor *parent;
3038
3039   /* Note we terminate before ever calling stage->apply_transform()
3040    * since that would conceptually be relative to the underlying
3041    * window OpenGL coordinates so we'd need a special @ancestor
3042    * value to represent the fake parent of the stage. */
3043   if (self == ancestor)
3044     return;
3045
3046   parent = clutter_actor_get_parent (self);
3047
3048   if (parent != NULL)
3049     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
3050                                                          matrix);
3051
3052   _clutter_actor_apply_modelview_transform (self, matrix);
3053 }
3054
3055 static void
3056 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
3057                                        ClutterPaintVolume *pv,
3058                                        const char *label,
3059                                        const CoglColor *color)
3060 {
3061   static CoglPipeline *outline = NULL;
3062   CoglPrimitive *prim;
3063   ClutterVertex line_ends[12 * 2];
3064   int n_vertices;
3065   CoglContext *ctx =
3066     clutter_backend_get_cogl_context (clutter_get_default_backend ());
3067   /* XXX: at some point we'll query this from the stage but we can't
3068    * do that until the osx backend uses Cogl natively. */
3069   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
3070
3071   if (outline == NULL)
3072     outline = cogl_pipeline_new (ctx);
3073
3074   _clutter_paint_volume_complete (pv);
3075
3076   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3077
3078   /* Front face */
3079   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3080   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3081   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3082   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3083
3084   if (!pv->is_2d)
3085     {
3086       /* Back face */
3087       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3088       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3089       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3090       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3091
3092       /* Lines connecting front face to back face */
3093       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3094       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3095       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3096       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3097     }
3098
3099   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3100                                 n_vertices,
3101                                 (CoglVertexP3 *)line_ends);
3102
3103   cogl_pipeline_set_color (outline, color);
3104   cogl_framebuffer_draw_primitive (fb, outline, prim);
3105   cogl_object_unref (prim);
3106
3107   if (label)
3108     {
3109       PangoLayout *layout;
3110       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3111       pango_layout_set_text (layout, label, -1);
3112       cogl_pango_render_layout (layout,
3113                                 pv->vertices[0].x,
3114                                 pv->vertices[0].y,
3115                                 color,
3116                                 0);
3117       g_object_unref (layout);
3118     }
3119 }
3120
3121 static void
3122 _clutter_actor_draw_paint_volume (ClutterActor *self)
3123 {
3124   ClutterPaintVolume *pv;
3125   CoglColor color;
3126
3127   pv = _clutter_actor_get_paint_volume_mutable (self);
3128   if (!pv)
3129     {
3130       gfloat width, height;
3131       ClutterPaintVolume fake_pv;
3132
3133       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3134       _clutter_paint_volume_init_static (&fake_pv, stage);
3135
3136       clutter_actor_get_size (self, &width, &height);
3137       clutter_paint_volume_set_width (&fake_pv, width);
3138       clutter_paint_volume_set_height (&fake_pv, height);
3139
3140       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3141       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3142                                              _clutter_actor_get_debug_name (self),
3143                                              &color);
3144
3145       clutter_paint_volume_free (&fake_pv);
3146     }
3147   else
3148     {
3149       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3150       _clutter_actor_draw_paint_volume_full (self, pv,
3151                                              _clutter_actor_get_debug_name (self),
3152                                              &color);
3153     }
3154 }
3155
3156 static void
3157 _clutter_actor_paint_cull_result (ClutterActor *self,
3158                                   gboolean success,
3159                                   ClutterCullResult result)
3160 {
3161   ClutterPaintVolume *pv;
3162   CoglColor color;
3163
3164   if (success)
3165     {
3166       if (result == CLUTTER_CULL_RESULT_IN)
3167         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3168       else if (result == CLUTTER_CULL_RESULT_OUT)
3169         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3170       else
3171         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3172     }
3173   else
3174     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3175
3176   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3177     _clutter_actor_draw_paint_volume_full (self, pv,
3178                                            _clutter_actor_get_debug_name (self),
3179                                            &color);
3180   else
3181     {
3182       PangoLayout *layout;
3183       char *label =
3184         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3185       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3186       cogl_set_source_color (&color);
3187
3188       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3189       pango_layout_set_text (layout, label, -1);
3190       cogl_pango_render_layout (layout,
3191                                 0,
3192                                 0,
3193                                 &color,
3194                                 0);
3195       g_free (label);
3196       g_object_unref (layout);
3197     }
3198 }
3199
3200 static int clone_paint_level = 0;
3201
3202 void
3203 _clutter_actor_push_clone_paint (void)
3204 {
3205   clone_paint_level++;
3206 }
3207
3208 void
3209 _clutter_actor_pop_clone_paint (void)
3210 {
3211   clone_paint_level--;
3212 }
3213
3214 static gboolean
3215 in_clone_paint (void)
3216 {
3217   return clone_paint_level > 0;
3218 }
3219
3220 /* Returns TRUE if the actor can be ignored */
3221 /* FIXME: we should return a ClutterCullResult, and
3222  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3223  * means there's no point in trying to cull descendants of the current
3224  * node. */
3225 static gboolean
3226 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3227 {
3228   ClutterActorPrivate *priv = self->priv;
3229   ClutterActor *stage;
3230   const ClutterPlane *stage_clip;
3231
3232   if (!priv->last_paint_volume_valid)
3233     {
3234       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3235                     "->last_paint_volume_valid == FALSE",
3236                     _clutter_actor_get_debug_name (self));
3237       return FALSE;
3238     }
3239
3240   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3241     return FALSE;
3242
3243   stage = _clutter_actor_get_stage_internal (self);
3244   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3245   if (G_UNLIKELY (!stage_clip))
3246     {
3247       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3248                     "No stage clip set",
3249                     _clutter_actor_get_debug_name (self));
3250       return FALSE;
3251     }
3252
3253   if (cogl_get_draw_framebuffer () !=
3254       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3255     {
3256       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3257                     "Current framebuffer doesn't correspond to stage",
3258                     _clutter_actor_get_debug_name (self));
3259       return FALSE;
3260     }
3261
3262   *result_out =
3263     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3264   return TRUE;
3265 }
3266
3267 static void
3268 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3269 {
3270   ClutterActorPrivate *priv = self->priv;
3271   const ClutterPaintVolume *pv;
3272
3273   if (priv->last_paint_volume_valid)
3274     {
3275       clutter_paint_volume_free (&priv->last_paint_volume);
3276       priv->last_paint_volume_valid = FALSE;
3277     }
3278
3279   pv = clutter_actor_get_paint_volume (self);
3280   if (!pv)
3281     {
3282       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3283                     "Actor failed to report a paint volume",
3284                     _clutter_actor_get_debug_name (self));
3285       return;
3286     }
3287
3288   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3289
3290   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3291                                             NULL); /* eye coordinates */
3292
3293   priv->last_paint_volume_valid = TRUE;
3294 }
3295
3296 static inline gboolean
3297 actor_has_shader_data (ClutterActor *self)
3298 {
3299   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3300 }
3301
3302 guint32
3303 _clutter_actor_get_pick_id (ClutterActor *self)
3304 {
3305   if (self->priv->pick_id < 0)
3306     return 0;
3307
3308   return self->priv->pick_id;
3309 }
3310
3311 /* This is the same as clutter_actor_add_effect except that it doesn't
3312    queue a redraw and it doesn't notify on the effect property */
3313 static void
3314 _clutter_actor_add_effect_internal (ClutterActor  *self,
3315                                     ClutterEffect *effect)
3316 {
3317   ClutterActorPrivate *priv = self->priv;
3318
3319   if (priv->effects == NULL)
3320     {
3321       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3322       priv->effects->actor = self;
3323     }
3324
3325   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3326 }
3327
3328 /* This is the same as clutter_actor_remove_effect except that it doesn't
3329    queue a redraw and it doesn't notify on the effect property */
3330 static void
3331 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3332                                        ClutterEffect *effect)
3333 {
3334   ClutterActorPrivate *priv = self->priv;
3335
3336   if (priv->effects == NULL)
3337     return;
3338
3339   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3340
3341   if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3342     g_clear_object (&priv->effects);
3343 }
3344
3345 static gboolean
3346 needs_flatten_effect (ClutterActor *self)
3347 {
3348   ClutterActorPrivate *priv = self->priv;
3349
3350   if (G_UNLIKELY (clutter_paint_debug_flags &
3351                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3352     return FALSE;
3353
3354   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3355     return TRUE;
3356   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3357     {
3358       if (clutter_actor_get_paint_opacity (self) < 255 &&
3359           clutter_actor_has_overlaps (self))
3360         return TRUE;
3361     }
3362
3363   return FALSE;
3364 }
3365
3366 static void
3367 add_or_remove_flatten_effect (ClutterActor *self)
3368 {
3369   ClutterActorPrivate *priv = self->priv;
3370
3371   /* Add or remove the flatten effect depending on the
3372      offscreen-redirect property. */
3373   if (needs_flatten_effect (self))
3374     {
3375       if (priv->flatten_effect == NULL)
3376         {
3377           ClutterActorMeta *actor_meta;
3378           gint priority;
3379
3380           priv->flatten_effect = _clutter_flatten_effect_new ();
3381           /* Keep a reference to the effect so that we can queue
3382              redraws from it */
3383           g_object_ref_sink (priv->flatten_effect);
3384
3385           /* Set the priority of the effect to high so that it will
3386              always be applied to the actor first. It uses an internal
3387              priority so that it won't be visible to applications */
3388           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3389           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3390           _clutter_actor_meta_set_priority (actor_meta, priority);
3391
3392           /* This will add the effect without queueing a redraw */
3393           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3394         }
3395     }
3396   else
3397     {
3398       if (priv->flatten_effect != NULL)
3399         {
3400           /* Destroy the effect so that it will lose its fbo cache of
3401              the actor */
3402           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3403           g_clear_object (&priv->flatten_effect);
3404         }
3405     }
3406 }
3407
3408 static void
3409 clutter_actor_real_paint (ClutterActor *actor)
3410 {
3411   ClutterActorPrivate *priv = actor->priv;
3412   ClutterActor *iter;
3413
3414   for (iter = priv->first_child;
3415        iter != NULL;
3416        iter = iter->priv->next_sibling)
3417     {
3418       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3419                     _clutter_actor_get_debug_name (iter),
3420                     _clutter_actor_get_debug_name (actor),
3421                     iter->priv->allocation.x1,
3422                     iter->priv->allocation.y1,
3423                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3424                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3425
3426       clutter_actor_paint (iter);
3427     }
3428 }
3429
3430 static gboolean
3431 clutter_actor_paint_node (ClutterActor     *actor,
3432                           ClutterPaintNode *root)
3433 {
3434   ClutterActorPrivate *priv = actor->priv;
3435
3436   if (root == NULL)
3437     return FALSE;
3438
3439   if (priv->bg_color_set &&
3440       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3441     {
3442       ClutterPaintNode *node;
3443       ClutterColor bg_color;
3444       ClutterActorBox box;
3445
3446       box.x1 = 0.f;
3447       box.y1 = 0.f;
3448       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3449       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3450
3451       bg_color = priv->bg_color;
3452       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3453                      * priv->bg_color.alpha
3454                      / 255;
3455
3456       node = clutter_color_node_new (&bg_color);
3457       clutter_paint_node_set_name (node, "backgroundColor");
3458       clutter_paint_node_add_rectangle (node, &box);
3459       clutter_paint_node_add_child (root, node);
3460       clutter_paint_node_unref (node);
3461     }
3462
3463   if (priv->content != NULL)
3464     _clutter_content_paint_content (priv->content, actor, root);
3465
3466   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3467     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3468
3469   if (clutter_paint_node_get_n_children (root) == 0)
3470     return FALSE;
3471
3472 #ifdef CLUTTER_ENABLE_DEBUG
3473   if (CLUTTER_HAS_DEBUG (PAINT))
3474     {
3475       /* dump the tree only if we have one */
3476       _clutter_paint_node_dump_tree (root);
3477     }
3478 #endif /* CLUTTER_ENABLE_DEBUG */
3479
3480   _clutter_paint_node_paint (root);
3481
3482 #if 0
3483   /* XXX: Uncomment this when we disable emitting the paint signal */
3484   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3485 #endif
3486
3487   return TRUE;
3488 }
3489
3490 /**
3491  * clutter_actor_paint:
3492  * @self: A #ClutterActor
3493  *
3494  * Renders the actor to display.
3495  *
3496  * This function should not be called directly by applications.
3497  * Call clutter_actor_queue_redraw() to queue paints, instead.
3498  *
3499  * This function is context-aware, and will either cause a
3500  * regular paint or a pick paint.
3501  *
3502  * This function will emit the #ClutterActor::paint signal or
3503  * the #ClutterActor::pick signal, depending on the context.
3504  *
3505  * This function does not paint the actor if the actor is set to 0,
3506  * unless it is performing a pick paint.
3507  */
3508 void
3509 clutter_actor_paint (ClutterActor *self)
3510 {
3511   ClutterActorPrivate *priv;
3512   ClutterPickMode pick_mode;
3513   gboolean clip_set = FALSE;
3514   gboolean shader_applied = FALSE;
3515
3516   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3517                           "Actor real-paint counter",
3518                           "Increments each time any actor is painted",
3519                           0 /* no application private data */);
3520   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3521                           "Actor pick-paint counter",
3522                           "Increments each time any actor is painted "
3523                           "for picking",
3524                           0 /* no application private data */);
3525
3526   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3527
3528   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3529     return;
3530
3531   priv = self->priv;
3532
3533   pick_mode = _clutter_context_get_pick_mode ();
3534
3535   if (pick_mode == CLUTTER_PICK_NONE)
3536     priv->propagated_one_redraw = FALSE;
3537
3538   /* It's an important optimization that we consider painting of
3539    * actors with 0 opacity to be a NOP... */
3540   if (pick_mode == CLUTTER_PICK_NONE &&
3541       /* ignore top-levels, since they might be transparent */
3542       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3543       /* Use the override opacity if its been set */
3544       ((priv->opacity_override >= 0) ?
3545        priv->opacity_override : priv->opacity) == 0)
3546     return;
3547
3548   /* if we aren't paintable (not in a toplevel with all
3549    * parents paintable) then do nothing.
3550    */
3551   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3552     return;
3553
3554   /* mark that we are in the paint process */
3555   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3556
3557   cogl_push_matrix();
3558
3559   if (priv->enable_model_view_transform)
3560     {
3561       CoglMatrix matrix;
3562
3563       /* XXX: It could be better to cache the modelview with the actor
3564        * instead of progressively building up the transformations on
3565        * the matrix stack every time we paint. */
3566       cogl_get_modelview_matrix (&matrix);
3567       _clutter_actor_apply_modelview_transform (self, &matrix);
3568
3569 #ifdef CLUTTER_ENABLE_DEBUG
3570       /* Catch when out-of-band transforms have been made by actors not as part
3571        * of an apply_transform vfunc... */
3572       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3573         {
3574           CoglMatrix expected_matrix;
3575
3576           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3577                                                              &expected_matrix);
3578
3579           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3580             {
3581               GString *buf = g_string_sized_new (1024);
3582               ClutterActor *parent;
3583
3584               parent = self;
3585               while (parent != NULL)
3586                 {
3587                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3588
3589                   if (parent->priv->parent != NULL)
3590                     g_string_append (buf, "->");
3591
3592                   parent = parent->priv->parent;
3593                 }
3594
3595               g_warning ("Unexpected transform found when painting actor "
3596                          "\"%s\". This will be caused by one of the actor's "
3597                          "ancestors (%s) using the Cogl API directly to transform "
3598                          "children instead of using ::apply_transform().",
3599                          _clutter_actor_get_debug_name (self),
3600                          buf->str);
3601
3602               g_string_free (buf, TRUE);
3603             }
3604         }
3605 #endif /* CLUTTER_ENABLE_DEBUG */
3606
3607       cogl_set_modelview_matrix (&matrix);
3608     }
3609
3610   if (priv->has_clip)
3611     {
3612       cogl_clip_push_rectangle (priv->clip.x,
3613                                 priv->clip.y,
3614                                 priv->clip.x + priv->clip.width,
3615                                 priv->clip.y + priv->clip.height);
3616       clip_set = TRUE;
3617     }
3618   else if (priv->clip_to_allocation)
3619     {
3620       gfloat width, height;
3621
3622       width  = priv->allocation.x2 - priv->allocation.x1;
3623       height = priv->allocation.y2 - priv->allocation.y1;
3624
3625       cogl_clip_push_rectangle (0, 0, width, height);
3626       clip_set = TRUE;
3627     }
3628
3629   if (pick_mode == CLUTTER_PICK_NONE)
3630     {
3631       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3632
3633       /* We check whether we need to add the flatten effect before
3634          each paint so that we can avoid having a mechanism for
3635          applications to notify when the value of the
3636          has_overlaps virtual changes. */
3637       add_or_remove_flatten_effect (self);
3638     }
3639   else
3640     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3641
3642   /* We save the current paint volume so that the next time the
3643    * actor queues a redraw we can constrain the redraw to just
3644    * cover the union of the new bounding box and the old.
3645    *
3646    * We also fetch the current paint volume to perform culling so
3647    * we can avoid painting actors outside the current clip region.
3648    *
3649    * If we are painting inside a clone, we should neither update
3650    * the paint volume or use it to cull painting, since the paint
3651    * box represents the location of the source actor on the
3652    * screen.
3653    *
3654    * XXX: We are starting to do a lot of vertex transforms on
3655    * the CPU in a typical paint, so at some point we should
3656    * audit these and consider caching some things.
3657    *
3658    * NB: We don't perform culling while picking at this point because
3659    * clutter-stage.c doesn't setup the clipping planes appropriately.
3660    *
3661    * NB: We don't want to update the last-paint-volume during picking
3662    * because the last-paint-volume is used to determine the old screen
3663    * space location of an actor that has moved so we can know the
3664    * minimal region to redraw to clear an old view of the actor. If we
3665    * update this during picking then by the time we come around to
3666    * paint then the last-paint-volume would likely represent the new
3667    * actor position not the old.
3668    */
3669   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3670     {
3671       gboolean success;
3672       /* annoyingly gcc warns if uninitialized even though
3673        * the initialization is redundant :-( */
3674       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3675
3676       if (G_LIKELY ((clutter_paint_debug_flags &
3677                      (CLUTTER_DEBUG_DISABLE_CULLING |
3678                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3679                     (CLUTTER_DEBUG_DISABLE_CULLING |
3680                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3681         _clutter_actor_update_last_paint_volume (self);
3682
3683       success = cull_actor (self, &result);
3684
3685       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3686         _clutter_actor_paint_cull_result (self, success, result);
3687       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3688         goto done;
3689     }
3690
3691   if (priv->effects == NULL)
3692     {
3693       if (pick_mode == CLUTTER_PICK_NONE &&
3694           actor_has_shader_data (self))
3695         {
3696           _clutter_actor_shader_pre_paint (self, FALSE);
3697           shader_applied = TRUE;
3698         }
3699
3700       priv->next_effect_to_paint = NULL;
3701     }
3702   else
3703     priv->next_effect_to_paint =
3704       _clutter_meta_group_peek_metas (priv->effects);
3705
3706   clutter_actor_continue_paint (self);
3707
3708   if (shader_applied)
3709     _clutter_actor_shader_post_paint (self);
3710
3711   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3712                   pick_mode == CLUTTER_PICK_NONE))
3713     _clutter_actor_draw_paint_volume (self);
3714
3715 done:
3716   /* If we make it here then the actor has run through a complete
3717      paint run including all the effects so it's no longer dirty */
3718   if (pick_mode == CLUTTER_PICK_NONE)
3719     priv->is_dirty = FALSE;
3720
3721   if (clip_set)
3722     cogl_clip_pop();
3723
3724   cogl_pop_matrix();
3725
3726   /* paint sequence complete */
3727   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3728 }
3729
3730 /**
3731  * clutter_actor_continue_paint:
3732  * @self: A #ClutterActor
3733  *
3734  * Run the next stage of the paint sequence. This function should only
3735  * be called within the implementation of the ‘run’ virtual of a
3736  * #ClutterEffect. It will cause the run method of the next effect to
3737  * be applied, or it will paint the actual actor if the current effect
3738  * is the last effect in the chain.
3739  *
3740  * Since: 1.8
3741  */
3742 void
3743 clutter_actor_continue_paint (ClutterActor *self)
3744 {
3745   ClutterActorPrivate *priv;
3746
3747   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3748   /* This should only be called from with in the ‘run’ implementation
3749      of a ClutterEffect */
3750   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3751
3752   priv = self->priv;
3753
3754   /* Skip any effects that are disabled */
3755   while (priv->next_effect_to_paint &&
3756          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3757     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3758
3759   /* If this has come from the last effect then we'll just paint the
3760      actual actor */
3761   if (priv->next_effect_to_paint == NULL)
3762     {
3763       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3764         {
3765           ClutterPaintNode *dummy;
3766
3767           /* XXX - this will go away in 2.0, when we can get rid of this
3768            * stuff and switch to a pure retained render tree of PaintNodes
3769            * for the entire frame, starting from the Stage; the paint()
3770            * virtual function can then be called directly.
3771            */
3772           dummy = _clutter_dummy_node_new (self);
3773           clutter_paint_node_set_name (dummy, "Root");
3774
3775           /* XXX - for 1.12, we use the return value of paint_node() to
3776            * decide whether we should emit the ::paint signal.
3777            */
3778           clutter_actor_paint_node (self, dummy);
3779           clutter_paint_node_unref (dummy);
3780
3781           g_signal_emit (self, actor_signals[PAINT], 0);
3782         }
3783       else
3784         {
3785           ClutterColor col = { 0, };
3786
3787           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3788
3789           /* Actor will then paint silhouette of itself in supplied
3790            * color.  See clutter_stage_get_actor_at_pos() for where
3791            * picking is enabled.
3792            */
3793           g_signal_emit (self, actor_signals[PICK], 0, &col);
3794         }
3795     }
3796   else
3797     {
3798       ClutterEffect *old_current_effect;
3799       ClutterEffectPaintFlags run_flags = 0;
3800
3801       /* Cache the current effect so that we can put it back before
3802          returning */
3803       old_current_effect = priv->current_effect;
3804
3805       priv->current_effect = priv->next_effect_to_paint->data;
3806       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3807
3808       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3809         {
3810           if (priv->is_dirty)
3811             {
3812               /* If there's an effect queued with this redraw then all
3813                  effects up to that one will be considered dirty. It
3814                  is expected the queued effect will paint the cached
3815                  image and not call clutter_actor_continue_paint again
3816                  (although it should work ok if it does) */
3817               if (priv->effect_to_redraw == NULL ||
3818                   priv->current_effect != priv->effect_to_redraw)
3819                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3820             }
3821
3822           _clutter_effect_paint (priv->current_effect, run_flags);
3823         }
3824       else
3825         {
3826           /* We can't determine when an actor has been modified since
3827              its last pick so lets just assume it has always been
3828              modified */
3829           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3830
3831           _clutter_effect_pick (priv->current_effect, run_flags);
3832         }
3833
3834       priv->current_effect = old_current_effect;
3835     }
3836 }
3837
3838 static void
3839 _clutter_actor_stop_transitions (ClutterActor *self)
3840 {
3841   const ClutterAnimationInfo *info;
3842   GHashTableIter iter;
3843   gpointer value;
3844
3845   info = _clutter_actor_get_animation_info_or_defaults (self);
3846   if (info->transitions == NULL)
3847     return;
3848
3849   g_hash_table_iter_init (&iter, info->transitions);
3850   while (g_hash_table_iter_next (&iter, NULL, &value))
3851     {
3852       TransitionClosure *closure = value;
3853       clutter_timeline_stop (CLUTTER_TIMELINE (closure->transition));
3854     }
3855 }
3856
3857 static ClutterActorTraverseVisitFlags
3858 invalidate_queue_redraw_entry (ClutterActor *self,
3859                                int           depth,
3860                                gpointer      user_data)
3861 {
3862   ClutterActorPrivate *priv = self->priv;
3863
3864   if (priv->queue_redraw_entry != NULL)
3865     {
3866       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3867       priv->queue_redraw_entry = NULL;
3868     }
3869
3870   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3871 }
3872
3873 static inline void
3874 remove_child (ClutterActor *self,
3875               ClutterActor *child)
3876 {
3877   ClutterActor *prev_sibling, *next_sibling;
3878
3879   prev_sibling = child->priv->prev_sibling;
3880   next_sibling = child->priv->next_sibling;
3881
3882   if (prev_sibling != NULL)
3883     prev_sibling->priv->next_sibling = next_sibling;
3884
3885   if (next_sibling != NULL)
3886     next_sibling->priv->prev_sibling = prev_sibling;
3887
3888   if (self->priv->first_child == child)
3889     self->priv->first_child = next_sibling;
3890
3891   if (self->priv->last_child == child)
3892     self->priv->last_child = prev_sibling;
3893
3894   child->priv->parent = NULL;
3895   child->priv->prev_sibling = NULL;
3896   child->priv->next_sibling = NULL;
3897 }
3898
3899 typedef enum {
3900   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3901   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3902   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3903   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3904   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3905   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3906   REMOVE_CHILD_STOP_TRANSITIONS   = 1 << 6,
3907
3908   /* default flags for public API */
3909   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_STOP_TRANSITIONS |
3910                                     REMOVE_CHILD_DESTROY_META |
3911                                     REMOVE_CHILD_EMIT_PARENT_SET |
3912                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3913                                     REMOVE_CHILD_CHECK_STATE |
3914                                     REMOVE_CHILD_FLUSH_QUEUE |
3915                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3916
3917   /* flags for legacy/deprecated API */
3918   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_STOP_TRANSITIONS |
3919                                     REMOVE_CHILD_CHECK_STATE |
3920                                     REMOVE_CHILD_FLUSH_QUEUE |
3921                                     REMOVE_CHILD_EMIT_PARENT_SET |
3922                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3923 } ClutterActorRemoveChildFlags;
3924
3925 /*< private >
3926  * clutter_actor_remove_child_internal:
3927  * @self: a #ClutterActor
3928  * @child: the child of @self that has to be removed
3929  * @flags: control the removal operations
3930  *
3931  * Removes @child from the list of children of @self.
3932  */
3933 static void
3934 clutter_actor_remove_child_internal (ClutterActor                 *self,
3935                                      ClutterActor                 *child,
3936                                      ClutterActorRemoveChildFlags  flags)
3937 {
3938   ClutterActor *old_first, *old_last;
3939   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3940   gboolean flush_queue;
3941   gboolean notify_first_last;
3942   gboolean was_mapped;
3943   gboolean stop_transitions;
3944
3945   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3946   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3947   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3948   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3949   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3950   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3951   stop_transitions = (flags & REMOVE_CHILD_STOP_TRANSITIONS) != 0;
3952
3953   g_object_freeze_notify (G_OBJECT (self));
3954
3955   if (stop_transitions)
3956     _clutter_actor_stop_transitions (child);
3957
3958   if (destroy_meta)
3959     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3960
3961   if (check_state)
3962     {
3963       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3964
3965       /* we need to unrealize *before* we set parent_actor to NULL,
3966        * because in an unrealize method actors are dissociating from the
3967        * stage, which means they need to be able to
3968        * clutter_actor_get_stage().
3969        *
3970        * yhis should unmap and unrealize, unless we're reparenting.
3971        */
3972       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3973     }
3974   else
3975     was_mapped = FALSE;
3976
3977   if (flush_queue)
3978     {
3979       /* We take this opportunity to invalidate any queue redraw entry
3980        * associated with the actor and descendants since we won't be able to
3981        * determine the appropriate stage after this.
3982        *
3983        * we do this after we updated the mapped state because actors might
3984        * end up queueing redraws inside their mapped/unmapped virtual
3985        * functions, and if we invalidate the redraw entry we could end up
3986        * with an inconsistent state and weird memory corruption. see
3987        * bugs:
3988        *
3989        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3990        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3991        */
3992       _clutter_actor_traverse (child,
3993                                0,
3994                                invalidate_queue_redraw_entry,
3995                                NULL,
3996                                NULL);
3997     }
3998
3999   old_first = self->priv->first_child;
4000   old_last = self->priv->last_child;
4001
4002   remove_child (self, child);
4003
4004   self->priv->n_children -= 1;
4005
4006   self->priv->age += 1;
4007
4008   /* if the child that got removed was visible and set to
4009    * expand then we want to reset the parent's state in
4010    * case the child was the only thing that was making it
4011    * expand.
4012    */
4013   if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
4014       (child->priv->needs_compute_expand ||
4015        child->priv->needs_x_expand ||
4016        child->priv->needs_y_expand))
4017     {
4018       clutter_actor_queue_compute_expand (self);
4019     }
4020
4021   /* clutter_actor_reparent() will emit ::parent-set for us */
4022   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
4023     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
4024
4025   /* if the child was mapped then we need to relayout ourselves to account
4026    * for the removed child
4027    */
4028   if (was_mapped)
4029     clutter_actor_queue_relayout (self);
4030
4031   /* we need to emit the signal before dropping the reference */
4032   if (emit_actor_removed)
4033     g_signal_emit_by_name (self, "actor-removed", child);
4034
4035   if (notify_first_last)
4036     {
4037       if (old_first != self->priv->first_child)
4038         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
4039
4040       if (old_last != self->priv->last_child)
4041         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
4042     }
4043
4044   g_object_thaw_notify (G_OBJECT (self));
4045
4046   /* remove the reference we acquired in clutter_actor_add_child() */
4047   g_object_unref (child);
4048 }
4049
4050 static const ClutterTransformInfo default_transform_info = {
4051   0.0, { 0, },          /* rotation-x */
4052   0.0, { 0, },          /* rotation-y */
4053   0.0, { 0, },          /* rotation-z */
4054
4055   1.0, 1.0, { 0, },     /* scale */
4056
4057   { 0, },               /* anchor */
4058
4059   0.0,                  /* depth */
4060 };
4061
4062 /*< private >
4063  * _clutter_actor_get_transform_info_or_defaults:
4064  * @self: a #ClutterActor
4065  *
4066  * Retrieves the ClutterTransformInfo structure associated to an actor.
4067  *
4068  * If the actor does not have a ClutterTransformInfo structure associated
4069  * to it, then the default structure will be returned.
4070  *
4071  * This function should only be used for getters.
4072  *
4073  * Return value: a const pointer to the ClutterTransformInfo structure
4074  */
4075 const ClutterTransformInfo *
4076 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
4077 {
4078   ClutterTransformInfo *info;
4079
4080   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4081   if (info != NULL)
4082     return info;
4083
4084   return &default_transform_info;
4085 }
4086
4087 static void
4088 clutter_transform_info_free (gpointer data)
4089 {
4090   if (data != NULL)
4091     g_slice_free (ClutterTransformInfo, data);
4092 }
4093
4094 /*< private >
4095  * _clutter_actor_get_transform_info:
4096  * @self: a #ClutterActor
4097  *
4098  * Retrieves a pointer to the ClutterTransformInfo structure.
4099  *
4100  * If the actor does not have a ClutterTransformInfo associated to it, one
4101  * will be created and initialized to the default values.
4102  *
4103  * This function should be used for setters.
4104  *
4105  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
4106  * instead.
4107  *
4108  * Return value: (transfer none): a pointer to the ClutterTransformInfo
4109  *   structure
4110  */
4111 ClutterTransformInfo *
4112 _clutter_actor_get_transform_info (ClutterActor *self)
4113 {
4114   ClutterTransformInfo *info;
4115
4116   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4117   if (info == NULL)
4118     {
4119       info = g_slice_new (ClutterTransformInfo);
4120
4121       *info = default_transform_info;
4122
4123       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4124                                info,
4125                                clutter_transform_info_free);
4126     }
4127
4128   return info;
4129 }
4130
4131 /*< private >
4132  * clutter_actor_set_rotation_angle_internal:
4133  * @self: a #ClutterActor
4134  * @axis: the axis of the angle to change
4135  * @angle: the angle of rotation
4136  *
4137  * Sets the rotation angle on the given axis without affecting the
4138  * rotation center point.
4139  */
4140 static inline void
4141 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
4142                                            ClutterRotateAxis  axis,
4143                                            gdouble            angle)
4144 {
4145   GObject *obj = G_OBJECT (self);
4146   ClutterTransformInfo *info;
4147
4148   info = _clutter_actor_get_transform_info (self);
4149
4150   g_object_freeze_notify (obj);
4151
4152   switch (axis)
4153     {
4154     case CLUTTER_X_AXIS:
4155       info->rx_angle = angle;
4156       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4157       break;
4158
4159     case CLUTTER_Y_AXIS:
4160       info->ry_angle = angle;
4161       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4162       break;
4163
4164     case CLUTTER_Z_AXIS:
4165       info->rz_angle = angle;
4166       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4167       break;
4168     }
4169
4170   self->priv->transform_valid = FALSE;
4171
4172   g_object_thaw_notify (obj);
4173
4174   clutter_actor_queue_redraw (self);
4175 }
4176
4177 static inline void
4178 clutter_actor_set_rotation_angle (ClutterActor      *self,
4179                                   ClutterRotateAxis  axis,
4180                                   gdouble            angle)
4181 {
4182   const ClutterTransformInfo *info;
4183   const double *cur_angle_p = NULL;
4184   GParamSpec *pspec = NULL;
4185
4186   info = _clutter_actor_get_transform_info_or_defaults (self);
4187
4188   switch (axis)
4189     {
4190     case CLUTTER_X_AXIS:
4191       cur_angle_p = &info->rx_angle;
4192       pspec = obj_props[PROP_ROTATION_ANGLE_X];
4193       break;
4194
4195     case CLUTTER_Y_AXIS:
4196       cur_angle_p = &info->ry_angle;
4197       pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4198       break;
4199
4200     case CLUTTER_Z_AXIS:
4201       cur_angle_p = &info->rz_angle;
4202       pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4203       break;
4204     }
4205
4206   g_assert (pspec != NULL);
4207   g_assert (cur_angle_p != NULL);
4208
4209   if (_clutter_actor_get_transition (self, pspec) == NULL)
4210     _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4211   else
4212     _clutter_actor_update_transition (self, pspec, angle);
4213
4214   clutter_actor_queue_redraw (self);
4215 }
4216
4217 /*< private >
4218  * clutter_actor_set_rotation_center_internal:
4219  * @self: a #ClutterActor
4220  * @axis: the axis of the center to change
4221  * @center: the coordinates of the rotation center
4222  *
4223  * Sets the rotation center on the given axis without affecting the
4224  * rotation angle.
4225  */
4226 static inline void
4227 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4228                                             ClutterRotateAxis    axis,
4229                                             const ClutterVertex *center)
4230 {
4231   GObject *obj = G_OBJECT (self);
4232   ClutterTransformInfo *info;
4233   ClutterVertex v = { 0, 0, 0 };
4234
4235   info = _clutter_actor_get_transform_info (self);
4236
4237   if (center != NULL)
4238     v = *center;
4239
4240   g_object_freeze_notify (obj);
4241
4242   switch (axis)
4243     {
4244     case CLUTTER_X_AXIS:
4245       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4246       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4247       break;
4248
4249     case CLUTTER_Y_AXIS:
4250       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4251       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4252       break;
4253
4254     case CLUTTER_Z_AXIS:
4255       /* if the previously set rotation center was fractional, then
4256        * setting explicit coordinates will have to notify the
4257        * :rotation-center-z-gravity property as well
4258        */
4259       if (info->rz_center.is_fractional)
4260         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4261
4262       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4263       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4264       break;
4265     }
4266
4267   self->priv->transform_valid = FALSE;
4268
4269   g_object_thaw_notify (obj);
4270
4271   clutter_actor_queue_redraw (self);
4272 }
4273
4274 static void
4275 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4276                                          double factor,
4277                                          GParamSpec *pspec)
4278 {
4279   GObject *obj = G_OBJECT (self);
4280   ClutterTransformInfo *info;
4281
4282   info = _clutter_actor_get_transform_info (self);
4283
4284   if (pspec == obj_props[PROP_SCALE_X])
4285     info->scale_x = factor;
4286   else
4287     info->scale_y = factor;
4288
4289   self->priv->transform_valid = FALSE;
4290   clutter_actor_queue_redraw (self);
4291   g_object_notify_by_pspec (obj, pspec);
4292 }
4293
4294 static inline void
4295 clutter_actor_set_scale_factor (ClutterActor      *self,
4296                                 ClutterRotateAxis  axis,
4297                                 gdouble            factor)
4298 {
4299   const ClutterTransformInfo *info;
4300   const double *scale_p = NULL;
4301   GParamSpec *pspec = NULL;
4302
4303   info = _clutter_actor_get_transform_info_or_defaults (self);
4304
4305   switch (axis)
4306     {
4307     case CLUTTER_X_AXIS:
4308       pspec = obj_props[PROP_SCALE_X];
4309       scale_p = &info->scale_x;
4310       break;
4311
4312     case CLUTTER_Y_AXIS:
4313       pspec = obj_props[PROP_SCALE_Y];
4314       scale_p = &info->scale_y;
4315       break;
4316
4317     case CLUTTER_Z_AXIS:
4318       break;
4319     }
4320
4321   g_assert (pspec != NULL);
4322   g_assert (scale_p != NULL);
4323
4324   if (_clutter_actor_get_transition (self, pspec) == NULL)
4325     _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4326   else
4327     _clutter_actor_update_transition (self, pspec, factor);
4328
4329   clutter_actor_queue_redraw (self);
4330 }
4331
4332 static inline void
4333 clutter_actor_set_scale_center (ClutterActor      *self,
4334                                 ClutterRotateAxis  axis,
4335                                 gfloat             coord)
4336 {
4337   GObject *obj = G_OBJECT (self);
4338   ClutterTransformInfo *info;
4339   gfloat center_x, center_y;
4340
4341   info = _clutter_actor_get_transform_info (self);
4342
4343   g_object_freeze_notify (obj);
4344
4345   /* get the current scale center coordinates */
4346   clutter_anchor_coord_get_units (self, &info->scale_center,
4347                                   &center_x,
4348                                   &center_y,
4349                                   NULL);
4350
4351   /* we need to notify this too, because setting explicit coordinates will
4352    * change the gravity as a side effect
4353    */
4354   if (info->scale_center.is_fractional)
4355     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4356
4357   switch (axis)
4358     {
4359     case CLUTTER_X_AXIS:
4360       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4361       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4362       break;
4363
4364     case CLUTTER_Y_AXIS:
4365       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4366       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4367       break;
4368
4369     default:
4370       g_assert_not_reached ();
4371     }
4372
4373   self->priv->transform_valid = FALSE;
4374
4375   clutter_actor_queue_redraw (self);
4376
4377   g_object_thaw_notify (obj);
4378 }
4379
4380 static inline void
4381 clutter_actor_set_scale_gravity (ClutterActor   *self,
4382                                  ClutterGravity  gravity)
4383 {
4384   ClutterTransformInfo *info;
4385   GObject *obj;
4386
4387   info = _clutter_actor_get_transform_info (self);
4388   obj = G_OBJECT (self);
4389
4390   if (gravity == CLUTTER_GRAVITY_NONE)
4391     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4392   else
4393     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4394
4395   self->priv->transform_valid = FALSE;
4396
4397   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4398   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4399   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4400
4401   clutter_actor_queue_redraw (self);
4402 }
4403
4404 static inline void
4405 clutter_actor_set_anchor_coord (ClutterActor      *self,
4406                                 ClutterRotateAxis  axis,
4407                                 gfloat             coord)
4408 {
4409   GObject *obj = G_OBJECT (self);
4410   ClutterTransformInfo *info;
4411   gfloat anchor_x, anchor_y;
4412
4413   info = _clutter_actor_get_transform_info (self);
4414
4415   g_object_freeze_notify (obj);
4416
4417   clutter_anchor_coord_get_units (self, &info->anchor,
4418                                   &anchor_x,
4419                                   &anchor_y,
4420                                   NULL);
4421
4422   if (info->anchor.is_fractional)
4423     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4424
4425   switch (axis)
4426     {
4427     case CLUTTER_X_AXIS:
4428       clutter_anchor_coord_set_units (&info->anchor,
4429                                       coord,
4430                                       anchor_y,
4431                                       0.0);
4432       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4433       break;
4434
4435     case CLUTTER_Y_AXIS:
4436       clutter_anchor_coord_set_units (&info->anchor,
4437                                       anchor_x,
4438                                       coord,
4439                                       0.0);
4440       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4441       break;
4442
4443     default:
4444       g_assert_not_reached ();
4445     }
4446
4447   self->priv->transform_valid = FALSE;
4448
4449   clutter_actor_queue_redraw (self);
4450
4451   g_object_thaw_notify (obj);
4452 }
4453
4454 static void
4455 clutter_actor_set_property (GObject      *object,
4456                             guint         prop_id,
4457                             const GValue *value,
4458                             GParamSpec   *pspec)
4459 {
4460   ClutterActor *actor = CLUTTER_ACTOR (object);
4461   ClutterActorPrivate *priv = actor->priv;
4462
4463   switch (prop_id)
4464     {
4465     case PROP_X:
4466       clutter_actor_set_x (actor, g_value_get_float (value));
4467       break;
4468
4469     case PROP_Y:
4470       clutter_actor_set_y (actor, g_value_get_float (value));
4471       break;
4472
4473     case PROP_POSITION:
4474       {
4475         const ClutterPoint *pos = g_value_get_boxed (value);
4476
4477         if (pos != NULL)
4478           clutter_actor_set_position (actor, pos->x, pos->y);
4479         else
4480           clutter_actor_set_fixed_position_set (actor, FALSE);
4481       }
4482       break;
4483
4484     case PROP_WIDTH:
4485       clutter_actor_set_width (actor, g_value_get_float (value));
4486       break;
4487
4488     case PROP_HEIGHT:
4489       clutter_actor_set_height (actor, g_value_get_float (value));
4490       break;
4491
4492     case PROP_SIZE:
4493       {
4494         const ClutterSize *size = g_value_get_boxed (value);
4495
4496         if (size != NULL)
4497           clutter_actor_set_size (actor, size->width, size->height);
4498         else
4499           clutter_actor_set_size (actor, -1, -1);
4500       }
4501       break;
4502
4503     case PROP_FIXED_X:
4504       clutter_actor_set_x (actor, g_value_get_float (value));
4505       break;
4506
4507     case PROP_FIXED_Y:
4508       clutter_actor_set_y (actor, g_value_get_float (value));
4509       break;
4510
4511     case PROP_FIXED_POSITION_SET:
4512       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4513       break;
4514
4515     case PROP_MIN_WIDTH:
4516       clutter_actor_set_min_width (actor, g_value_get_float (value));
4517       break;
4518
4519     case PROP_MIN_HEIGHT:
4520       clutter_actor_set_min_height (actor, g_value_get_float (value));
4521       break;
4522
4523     case PROP_NATURAL_WIDTH:
4524       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4525       break;
4526
4527     case PROP_NATURAL_HEIGHT:
4528       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4529       break;
4530
4531     case PROP_MIN_WIDTH_SET:
4532       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4533       break;
4534
4535     case PROP_MIN_HEIGHT_SET:
4536       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4537       break;
4538
4539     case PROP_NATURAL_WIDTH_SET:
4540       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4541       break;
4542
4543     case PROP_NATURAL_HEIGHT_SET:
4544       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4545       break;
4546
4547     case PROP_REQUEST_MODE:
4548       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4549       break;
4550
4551     case PROP_DEPTH:
4552       clutter_actor_set_depth (actor, g_value_get_float (value));
4553       break;
4554
4555     case PROP_OPACITY:
4556       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4557       break;
4558
4559     case PROP_OFFSCREEN_REDIRECT:
4560       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4561       break;
4562
4563     case PROP_NAME:
4564       clutter_actor_set_name (actor, g_value_get_string (value));
4565       break;
4566
4567     case PROP_VISIBLE:
4568       if (g_value_get_boolean (value) == TRUE)
4569         clutter_actor_show (actor);
4570       else
4571         clutter_actor_hide (actor);
4572       break;
4573
4574     case PROP_SCALE_X:
4575       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4576                                       g_value_get_double (value));
4577       break;
4578
4579     case PROP_SCALE_Y:
4580       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4581                                       g_value_get_double (value));
4582       break;
4583
4584     case PROP_SCALE_CENTER_X:
4585       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4586                                       g_value_get_float (value));
4587       break;
4588
4589     case PROP_SCALE_CENTER_Y:
4590       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4591                                       g_value_get_float (value));
4592       break;
4593
4594     case PROP_SCALE_GRAVITY:
4595       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4596       break;
4597
4598     case PROP_CLIP:
4599       {
4600         const ClutterGeometry *geom = g_value_get_boxed (value);
4601
4602         clutter_actor_set_clip (actor,
4603                                 geom->x, geom->y,
4604                                 geom->width, geom->height);
4605       }
4606       break;
4607
4608     case PROP_CLIP_TO_ALLOCATION:
4609       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4610       break;
4611
4612     case PROP_REACTIVE:
4613       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4614       break;
4615
4616     case PROP_ROTATION_ANGLE_X:
4617       clutter_actor_set_rotation_angle (actor,
4618                                         CLUTTER_X_AXIS,
4619                                         g_value_get_double (value));
4620       break;
4621
4622     case PROP_ROTATION_ANGLE_Y:
4623       clutter_actor_set_rotation_angle (actor,
4624                                         CLUTTER_Y_AXIS,
4625                                         g_value_get_double (value));
4626       break;
4627
4628     case PROP_ROTATION_ANGLE_Z:
4629       clutter_actor_set_rotation_angle (actor,
4630                                         CLUTTER_Z_AXIS,
4631                                         g_value_get_double (value));
4632       break;
4633
4634     case PROP_ROTATION_CENTER_X:
4635       clutter_actor_set_rotation_center_internal (actor,
4636                                                   CLUTTER_X_AXIS,
4637                                                   g_value_get_boxed (value));
4638       break;
4639
4640     case PROP_ROTATION_CENTER_Y:
4641       clutter_actor_set_rotation_center_internal (actor,
4642                                                   CLUTTER_Y_AXIS,
4643                                                   g_value_get_boxed (value));
4644       break;
4645
4646     case PROP_ROTATION_CENTER_Z:
4647       clutter_actor_set_rotation_center_internal (actor,
4648                                                   CLUTTER_Z_AXIS,
4649                                                   g_value_get_boxed (value));
4650       break;
4651
4652     case PROP_ROTATION_CENTER_Z_GRAVITY:
4653       {
4654         const ClutterTransformInfo *info;
4655
4656         info = _clutter_actor_get_transform_info_or_defaults (actor);
4657         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4658                                                    g_value_get_enum (value));
4659       }
4660       break;
4661
4662     case PROP_ANCHOR_X:
4663       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4664                                       g_value_get_float (value));
4665       break;
4666
4667     case PROP_ANCHOR_Y:
4668       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4669                                       g_value_get_float (value));
4670       break;
4671
4672     case PROP_ANCHOR_GRAVITY:
4673       clutter_actor_set_anchor_point_from_gravity (actor,
4674                                                    g_value_get_enum (value));
4675       break;
4676
4677     case PROP_SHOW_ON_SET_PARENT:
4678       priv->show_on_set_parent = g_value_get_boolean (value);
4679       break;
4680
4681     case PROP_TEXT_DIRECTION:
4682       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4683       break;
4684
4685     case PROP_ACTIONS:
4686       clutter_actor_add_action (actor, g_value_get_object (value));
4687       break;
4688
4689     case PROP_CONSTRAINTS:
4690       clutter_actor_add_constraint (actor, g_value_get_object (value));
4691       break;
4692
4693     case PROP_EFFECT:
4694       clutter_actor_add_effect (actor, g_value_get_object (value));
4695       break;
4696
4697     case PROP_LAYOUT_MANAGER:
4698       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4699       break;
4700
4701     case PROP_X_EXPAND:
4702       clutter_actor_set_x_expand (actor, g_value_get_boolean (value));
4703       break;
4704
4705     case PROP_Y_EXPAND:
4706       clutter_actor_set_y_expand (actor, g_value_get_boolean (value));
4707       break;
4708
4709     case PROP_X_ALIGN:
4710       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4711       break;
4712
4713     case PROP_Y_ALIGN:
4714       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4715       break;
4716
4717     case PROP_MARGIN_TOP:
4718       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4719       break;
4720
4721     case PROP_MARGIN_BOTTOM:
4722       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4723       break;
4724
4725     case PROP_MARGIN_LEFT:
4726       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4727       break;
4728
4729     case PROP_MARGIN_RIGHT:
4730       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4731       break;
4732
4733     case PROP_BACKGROUND_COLOR:
4734       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4735       break;
4736
4737     case PROP_CONTENT:
4738       clutter_actor_set_content (actor, g_value_get_object (value));
4739       break;
4740
4741     case PROP_CONTENT_GRAVITY:
4742       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4743       break;
4744
4745     case PROP_MINIFICATION_FILTER:
4746       clutter_actor_set_content_scaling_filters (actor,
4747                                                  g_value_get_enum (value),
4748                                                  actor->priv->mag_filter);
4749       break;
4750
4751     case PROP_MAGNIFICATION_FILTER:
4752       clutter_actor_set_content_scaling_filters (actor,
4753                                                  actor->priv->min_filter,
4754                                                  g_value_get_enum (value));
4755       break;
4756
4757     default:
4758       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4759       break;
4760     }
4761 }
4762
4763 static void
4764 clutter_actor_get_property (GObject    *object,
4765                             guint       prop_id,
4766                             GValue     *value,
4767                             GParamSpec *pspec)
4768 {
4769   ClutterActor *actor = CLUTTER_ACTOR (object);
4770   ClutterActorPrivate *priv = actor->priv;
4771
4772   switch (prop_id)
4773     {
4774     case PROP_X:
4775       g_value_set_float (value, clutter_actor_get_x (actor));
4776       break;
4777
4778     case PROP_Y:
4779       g_value_set_float (value, clutter_actor_get_y (actor));
4780       break;
4781
4782     case PROP_POSITION:
4783       {
4784         ClutterPoint position;
4785
4786         clutter_point_init (&position,
4787                             clutter_actor_get_x (actor),
4788                             clutter_actor_get_y (actor));
4789         g_value_set_boxed (value, &position);
4790       }
4791       break;
4792
4793     case PROP_WIDTH:
4794       g_value_set_float (value, clutter_actor_get_width (actor));
4795       break;
4796
4797     case PROP_HEIGHT:
4798       g_value_set_float (value, clutter_actor_get_height (actor));
4799       break;
4800
4801     case PROP_SIZE:
4802       {
4803         ClutterSize size;
4804
4805         clutter_size_init (&size,
4806                            clutter_actor_get_width (actor),
4807                            clutter_actor_get_height (actor));
4808         g_value_set_boxed (value, &size);
4809       }
4810       break;
4811
4812     case PROP_FIXED_X:
4813       {
4814         const ClutterLayoutInfo *info;
4815
4816         info = _clutter_actor_get_layout_info_or_defaults (actor);
4817         g_value_set_float (value, info->fixed_pos.x);
4818       }
4819       break;
4820
4821     case PROP_FIXED_Y:
4822       {
4823         const ClutterLayoutInfo *info;
4824
4825         info = _clutter_actor_get_layout_info_or_defaults (actor);
4826         g_value_set_float (value, info->fixed_pos.y);
4827       }
4828       break;
4829
4830     case PROP_FIXED_POSITION_SET:
4831       g_value_set_boolean (value, priv->position_set);
4832       break;
4833
4834     case PROP_MIN_WIDTH:
4835       {
4836         const ClutterLayoutInfo *info;
4837
4838         info = _clutter_actor_get_layout_info_or_defaults (actor);
4839         g_value_set_float (value, info->minimum.width);
4840       }
4841       break;
4842
4843     case PROP_MIN_HEIGHT:
4844       {
4845         const ClutterLayoutInfo *info;
4846
4847         info = _clutter_actor_get_layout_info_or_defaults (actor);
4848         g_value_set_float (value, info->minimum.height);
4849       }
4850       break;
4851
4852     case PROP_NATURAL_WIDTH:
4853       {
4854         const ClutterLayoutInfo *info;
4855
4856         info = _clutter_actor_get_layout_info_or_defaults (actor);
4857         g_value_set_float (value, info->natural.width);
4858       }
4859       break;
4860
4861     case PROP_NATURAL_HEIGHT:
4862       {
4863         const ClutterLayoutInfo *info;
4864
4865         info = _clutter_actor_get_layout_info_or_defaults (actor);
4866         g_value_set_float (value, info->natural.height);
4867       }
4868       break;
4869
4870     case PROP_MIN_WIDTH_SET:
4871       g_value_set_boolean (value, priv->min_width_set);
4872       break;
4873
4874     case PROP_MIN_HEIGHT_SET:
4875       g_value_set_boolean (value, priv->min_height_set);
4876       break;
4877
4878     case PROP_NATURAL_WIDTH_SET:
4879       g_value_set_boolean (value, priv->natural_width_set);
4880       break;
4881
4882     case PROP_NATURAL_HEIGHT_SET:
4883       g_value_set_boolean (value, priv->natural_height_set);
4884       break;
4885
4886     case PROP_REQUEST_MODE:
4887       g_value_set_enum (value, priv->request_mode);
4888       break;
4889
4890     case PROP_ALLOCATION:
4891       g_value_set_boxed (value, &priv->allocation);
4892       break;
4893
4894     case PROP_DEPTH:
4895       g_value_set_float (value, clutter_actor_get_depth (actor));
4896       break;
4897
4898     case PROP_OPACITY:
4899       g_value_set_uint (value, priv->opacity);
4900       break;
4901
4902     case PROP_OFFSCREEN_REDIRECT:
4903       g_value_set_enum (value, priv->offscreen_redirect);
4904       break;
4905
4906     case PROP_NAME:
4907       g_value_set_string (value, priv->name);
4908       break;
4909
4910     case PROP_VISIBLE:
4911       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4912       break;
4913
4914     case PROP_MAPPED:
4915       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4916       break;
4917
4918     case PROP_REALIZED:
4919       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4920       break;
4921
4922     case PROP_HAS_CLIP:
4923       g_value_set_boolean (value, priv->has_clip);
4924       break;
4925
4926     case PROP_CLIP:
4927       {
4928         ClutterGeometry clip;
4929
4930         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4931         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4932         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4933         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4934
4935         g_value_set_boxed (value, &clip);
4936       }
4937       break;
4938
4939     case PROP_CLIP_TO_ALLOCATION:
4940       g_value_set_boolean (value, priv->clip_to_allocation);
4941       break;
4942
4943     case PROP_SCALE_X:
4944       {
4945         const ClutterTransformInfo *info;
4946
4947         info = _clutter_actor_get_transform_info_or_defaults (actor);
4948         g_value_set_double (value, info->scale_x);
4949       }
4950       break;
4951
4952     case PROP_SCALE_Y:
4953       {
4954         const ClutterTransformInfo *info;
4955
4956         info = _clutter_actor_get_transform_info_or_defaults (actor);
4957         g_value_set_double (value, info->scale_y);
4958       }
4959       break;
4960
4961     case PROP_SCALE_CENTER_X:
4962       {
4963         gfloat center;
4964
4965         clutter_actor_get_scale_center (actor, &center, NULL);
4966
4967         g_value_set_float (value, center);
4968       }
4969       break;
4970
4971     case PROP_SCALE_CENTER_Y:
4972       {
4973         gfloat center;
4974
4975         clutter_actor_get_scale_center (actor, NULL, &center);
4976
4977         g_value_set_float (value, center);
4978       }
4979       break;
4980
4981     case PROP_SCALE_GRAVITY:
4982       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4983       break;
4984
4985     case PROP_REACTIVE:
4986       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4987       break;
4988
4989     case PROP_ROTATION_ANGLE_X:
4990       {
4991         const ClutterTransformInfo *info;
4992
4993         info = _clutter_actor_get_transform_info_or_defaults (actor);
4994         g_value_set_double (value, info->rx_angle);
4995       }
4996       break;
4997
4998     case PROP_ROTATION_ANGLE_Y:
4999       {
5000         const ClutterTransformInfo *info;
5001
5002         info = _clutter_actor_get_transform_info_or_defaults (actor);
5003         g_value_set_double (value, info->ry_angle);
5004       }
5005       break;
5006
5007     case PROP_ROTATION_ANGLE_Z:
5008       {
5009         const ClutterTransformInfo *info;
5010
5011         info = _clutter_actor_get_transform_info_or_defaults (actor);
5012         g_value_set_double (value, info->rz_angle);
5013       }
5014       break;
5015
5016     case PROP_ROTATION_CENTER_X:
5017       {
5018         ClutterVertex center;
5019
5020         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
5021                                     &center.x,
5022                                     &center.y,
5023                                     &center.z);
5024
5025         g_value_set_boxed (value, &center);
5026       }
5027       break;
5028
5029     case PROP_ROTATION_CENTER_Y:
5030       {
5031         ClutterVertex center;
5032
5033         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
5034                                     &center.x,
5035                                     &center.y,
5036                                     &center.z);
5037
5038         g_value_set_boxed (value, &center);
5039       }
5040       break;
5041
5042     case PROP_ROTATION_CENTER_Z:
5043       {
5044         ClutterVertex center;
5045
5046         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
5047                                     &center.x,
5048                                     &center.y,
5049                                     &center.z);
5050
5051         g_value_set_boxed (value, &center);
5052       }
5053       break;
5054
5055     case PROP_ROTATION_CENTER_Z_GRAVITY:
5056       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
5057       break;
5058
5059     case PROP_ANCHOR_X:
5060       {
5061         const ClutterTransformInfo *info;
5062         gfloat anchor_x;
5063
5064         info = _clutter_actor_get_transform_info_or_defaults (actor);
5065         clutter_anchor_coord_get_units (actor, &info->anchor,
5066                                         &anchor_x,
5067                                         NULL,
5068                                         NULL);
5069         g_value_set_float (value, anchor_x);
5070       }
5071       break;
5072
5073     case PROP_ANCHOR_Y:
5074       {
5075         const ClutterTransformInfo *info;
5076         gfloat anchor_y;
5077
5078         info = _clutter_actor_get_transform_info_or_defaults (actor);
5079         clutter_anchor_coord_get_units (actor, &info->anchor,
5080                                         NULL,
5081                                         &anchor_y,
5082                                         NULL);
5083         g_value_set_float (value, anchor_y);
5084       }
5085       break;
5086
5087     case PROP_ANCHOR_GRAVITY:
5088       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
5089       break;
5090
5091     case PROP_SHOW_ON_SET_PARENT:
5092       g_value_set_boolean (value, priv->show_on_set_parent);
5093       break;
5094
5095     case PROP_TEXT_DIRECTION:
5096       g_value_set_enum (value, priv->text_direction);
5097       break;
5098
5099     case PROP_HAS_POINTER:
5100       g_value_set_boolean (value, priv->has_pointer);
5101       break;
5102
5103     case PROP_LAYOUT_MANAGER:
5104       g_value_set_object (value, priv->layout_manager);
5105       break;
5106
5107     case PROP_X_EXPAND:
5108       {
5109         const ClutterLayoutInfo *info;
5110
5111         info = _clutter_actor_get_layout_info_or_defaults (actor);
5112         g_value_set_boolean (value, info->x_expand);
5113       }
5114       break;
5115
5116     case PROP_Y_EXPAND:
5117       {
5118         const ClutterLayoutInfo *info;
5119
5120         info = _clutter_actor_get_layout_info_or_defaults (actor);
5121         g_value_set_boolean (value, info->y_expand);
5122       }
5123       break;
5124
5125     case PROP_X_ALIGN:
5126       {
5127         const ClutterLayoutInfo *info;
5128
5129         info = _clutter_actor_get_layout_info_or_defaults (actor);
5130         g_value_set_enum (value, info->x_align);
5131       }
5132       break;
5133
5134     case PROP_Y_ALIGN:
5135       {
5136         const ClutterLayoutInfo *info;
5137
5138         info = _clutter_actor_get_layout_info_or_defaults (actor);
5139         g_value_set_enum (value, info->y_align);
5140       }
5141       break;
5142
5143     case PROP_MARGIN_TOP:
5144       {
5145         const ClutterLayoutInfo *info;
5146
5147         info = _clutter_actor_get_layout_info_or_defaults (actor);
5148         g_value_set_float (value, info->margin.top);
5149       }
5150       break;
5151
5152     case PROP_MARGIN_BOTTOM:
5153       {
5154         const ClutterLayoutInfo *info;
5155
5156         info = _clutter_actor_get_layout_info_or_defaults (actor);
5157         g_value_set_float (value, info->margin.bottom);
5158       }
5159       break;
5160
5161     case PROP_MARGIN_LEFT:
5162       {
5163         const ClutterLayoutInfo *info;
5164
5165         info = _clutter_actor_get_layout_info_or_defaults (actor);
5166         g_value_set_float (value, info->margin.left);
5167       }
5168       break;
5169
5170     case PROP_MARGIN_RIGHT:
5171       {
5172         const ClutterLayoutInfo *info;
5173
5174         info = _clutter_actor_get_layout_info_or_defaults (actor);
5175         g_value_set_float (value, info->margin.right);
5176       }
5177       break;
5178
5179     case PROP_BACKGROUND_COLOR_SET:
5180       g_value_set_boolean (value, priv->bg_color_set);
5181       break;
5182
5183     case PROP_BACKGROUND_COLOR:
5184       g_value_set_boxed (value, &priv->bg_color);
5185       break;
5186
5187     case PROP_FIRST_CHILD:
5188       g_value_set_object (value, priv->first_child);
5189       break;
5190
5191     case PROP_LAST_CHILD:
5192       g_value_set_object (value, priv->last_child);
5193       break;
5194
5195     case PROP_CONTENT:
5196       g_value_set_object (value, priv->content);
5197       break;
5198
5199     case PROP_CONTENT_GRAVITY:
5200       g_value_set_enum (value, priv->content_gravity);
5201       break;
5202
5203     case PROP_CONTENT_BOX:
5204       {
5205         ClutterActorBox box = { 0, };
5206
5207         clutter_actor_get_content_box (actor, &box);
5208         g_value_set_boxed (value, &box);
5209       }
5210       break;
5211
5212     case PROP_MINIFICATION_FILTER:
5213       g_value_set_enum (value, priv->min_filter);
5214       break;
5215
5216     case PROP_MAGNIFICATION_FILTER:
5217       g_value_set_enum (value, priv->mag_filter);
5218       break;
5219
5220     default:
5221       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5222       break;
5223     }
5224 }
5225
5226 static void
5227 clutter_actor_dispose (GObject *object)
5228 {
5229   ClutterActor *self = CLUTTER_ACTOR (object);
5230   ClutterActorPrivate *priv = self->priv;
5231
5232   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5233                 priv->id,
5234                 g_type_name (G_OBJECT_TYPE (self)),
5235                 object->ref_count);
5236
5237   g_signal_emit (self, actor_signals[DESTROY], 0);
5238
5239   /* avoid recursing when called from clutter_actor_destroy() */
5240   if (priv->parent != NULL)
5241     {
5242       ClutterActor *parent = priv->parent;
5243
5244       /* go through the Container implementation unless this
5245        * is an internal child and has been marked as such.
5246        *
5247        * removing the actor from its parent will reset the
5248        * realized and mapped states.
5249        */
5250       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5251         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5252       else
5253         clutter_actor_remove_child_internal (parent, self,
5254                                              REMOVE_CHILD_LEGACY_FLAGS);
5255     }
5256
5257   /* parent must be gone at this point */
5258   g_assert (priv->parent == NULL);
5259
5260   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5261     {
5262       /* can't be mapped or realized with no parent */
5263       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5264       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5265     }
5266
5267   g_clear_object (&priv->pango_context);
5268   g_clear_object (&priv->actions);
5269   g_clear_object (&priv->constraints);
5270   g_clear_object (&priv->effects);
5271   g_clear_object (&priv->flatten_effect);
5272
5273   if (priv->layout_manager != NULL)
5274     {
5275       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5276       g_clear_object (&priv->layout_manager);
5277     }
5278
5279   if (priv->content != NULL)
5280     {
5281       _clutter_content_detached (priv->content, self);
5282       g_clear_object (&priv->content);
5283     }
5284
5285   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5286 }
5287
5288 static void
5289 clutter_actor_finalize (GObject *object)
5290 {
5291   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5292
5293   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5294                 priv->name != NULL ? priv->name : "<none>",
5295                 priv->id,
5296                 g_type_name (G_OBJECT_TYPE (object)));
5297
5298   _clutter_context_release_id (priv->id);
5299
5300   g_free (priv->name);
5301
5302 #ifdef CLUTTER_ENABLE_DEBUG
5303   g_free (priv->debug_name);
5304 #endif
5305
5306   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5307 }
5308
5309
5310 /**
5311  * clutter_actor_get_accessible:
5312  * @self: a #ClutterActor
5313  *
5314  * Returns the accessible object that describes the actor to an
5315  * assistive technology.
5316  *
5317  * If no class-specific #AtkObject implementation is available for the
5318  * actor instance in question, it will inherit an #AtkObject
5319  * implementation from the first ancestor class for which such an
5320  * implementation is defined.
5321  *
5322  * The documentation of the <ulink
5323  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5324  * library contains more information about accessible objects and
5325  * their uses.
5326  *
5327  * Returns: (transfer none): the #AtkObject associated with @actor
5328  */
5329 AtkObject *
5330 clutter_actor_get_accessible (ClutterActor *self)
5331 {
5332   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5333
5334   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5335 }
5336
5337 static AtkObject *
5338 clutter_actor_real_get_accessible (ClutterActor *actor)
5339 {
5340   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5341 }
5342
5343 static AtkObject *
5344 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5345 {
5346   AtkObject *accessible;
5347
5348   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5349   if (accessible != NULL)
5350     g_object_ref (accessible);
5351
5352   return accessible;
5353 }
5354
5355 static void
5356 atk_implementor_iface_init (AtkImplementorIface *iface)
5357 {
5358   iface->ref_accessible = _clutter_actor_ref_accessible;
5359 }
5360
5361 static gboolean
5362 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5363                                            ClutterPaintVolume *volume)
5364 {
5365   ClutterActorPrivate *priv = self->priv;
5366   gboolean res = TRUE;
5367
5368   /* we start from the allocation */
5369   clutter_paint_volume_set_width (volume,
5370                                   priv->allocation.x2 - priv->allocation.x1);
5371   clutter_paint_volume_set_height (volume,
5372                                    priv->allocation.y2 - priv->allocation.y1);
5373
5374   /* if the actor has a clip set then we have a pretty definite
5375    * size for the paint volume: the actor cannot possibly paint
5376    * outside the clip region.
5377    */
5378   if (priv->clip_to_allocation)
5379     {
5380       /* the allocation has already been set, so we just flip the
5381        * return value
5382        */
5383       res = TRUE;
5384     }
5385   else
5386     {
5387       ClutterActor *child;
5388
5389       if (priv->has_clip &&
5390           priv->clip.width >= 0 &&
5391           priv->clip.height >= 0)
5392         {
5393           ClutterVertex origin;
5394
5395           origin.x = priv->clip.x;
5396           origin.y = priv->clip.y;
5397           origin.z = 0;
5398
5399           clutter_paint_volume_set_origin (volume, &origin);
5400           clutter_paint_volume_set_width (volume, priv->clip.width);
5401           clutter_paint_volume_set_height (volume, priv->clip.height);
5402
5403           res = TRUE;
5404         }
5405
5406       /* if we don't have children we just bail out here... */
5407       if (priv->n_children == 0)
5408         return res;
5409
5410       /* ...but if we have children then we ask for their paint volume in
5411        * our coordinates. if any of our children replies that it doesn't
5412        * have a paint volume, we bail out
5413        */
5414       for (child = priv->first_child;
5415            child != NULL;
5416            child = child->priv->next_sibling)
5417         {
5418           const ClutterPaintVolume *child_volume;
5419
5420           if (!CLUTTER_ACTOR_IS_MAPPED (child))
5421             continue;
5422
5423           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5424           if (child_volume == NULL)
5425             {
5426               res = FALSE;
5427               break;
5428             }
5429
5430           clutter_paint_volume_union (volume, child_volume);
5431           res = TRUE;
5432         }
5433     }
5434
5435   return res;
5436
5437 }
5438
5439 static gboolean
5440 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5441                                      ClutterPaintVolume *volume)
5442 {
5443   ClutterActorClass *klass;
5444   gboolean res;
5445
5446   klass = CLUTTER_ACTOR_GET_CLASS (self);
5447
5448   /* XXX - this thoroughly sucks, but we don't want to penalize users
5449    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5450    * redraw. This should go away in 2.0.
5451    */
5452   if (klass->paint == clutter_actor_real_paint &&
5453       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5454     {
5455       res = TRUE;
5456     }
5457   else
5458     {
5459       /* this is the default return value: we cannot know if a class
5460        * is going to paint outside its allocation, so we take the
5461        * conservative approach.
5462        */
5463       res = FALSE;
5464     }
5465
5466   /* update_default_paint_volume() should only fail if one of the children
5467    * reported an invalid, or no, paint volume
5468    */
5469   if (!clutter_actor_update_default_paint_volume (self, volume))
5470     return FALSE;
5471
5472   return res;
5473 }
5474
5475 /**
5476  * clutter_actor_get_default_paint_volume:
5477  * @self: a #ClutterActor
5478  *
5479  * Retrieves the default paint volume for @self.
5480  *
5481  * This function provides the same #ClutterPaintVolume that would be
5482  * computed by the default implementation inside #ClutterActor of the
5483  * #ClutterActorClass.get_paint_volume() virtual function.
5484  *
5485  * This function should only be used by #ClutterActor subclasses that
5486  * cannot chain up to the parent implementation when computing their
5487  * paint volume.
5488  *
5489  * Return value: (transfer none): a pointer to the default
5490  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5491  *   the actor could not compute a valid paint volume. The returned value
5492  *   is not guaranteed to be stable across multiple frames, so if you
5493  *   want to retain it, you will need to copy it using
5494  *   clutter_paint_volume_copy().
5495  *
5496  * Since: 1.10
5497  */
5498 const ClutterPaintVolume *
5499 clutter_actor_get_default_paint_volume (ClutterActor *self)
5500 {
5501   ClutterPaintVolume volume;
5502   ClutterPaintVolume *res;
5503
5504   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5505
5506   res = NULL;
5507   _clutter_paint_volume_init_static (&volume, self);
5508   if (clutter_actor_update_default_paint_volume (self, &volume))
5509     {
5510       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5511
5512       if (stage != NULL)
5513         {
5514           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5515           _clutter_paint_volume_copy_static (&volume, res);
5516         }
5517     }
5518
5519   clutter_paint_volume_free (&volume);
5520
5521   return res;
5522 }
5523
5524 static gboolean
5525 clutter_actor_real_has_overlaps (ClutterActor *self)
5526 {
5527   /* By default we'll assume that all actors need an offscreen redirect to get
5528    * the correct opacity. Actors such as ClutterTexture that would never need
5529    * an offscreen redirect can override this to return FALSE. */
5530   return TRUE;
5531 }
5532
5533 static void
5534 clutter_actor_real_destroy (ClutterActor *actor)
5535 {
5536   ClutterActorIter iter;
5537
5538   g_object_freeze_notify (G_OBJECT (actor));
5539
5540   clutter_actor_iter_init (&iter, actor);
5541   while (clutter_actor_iter_next (&iter, NULL))
5542     clutter_actor_iter_destroy (&iter);
5543
5544   g_object_thaw_notify (G_OBJECT (actor));
5545 }
5546
5547 static GObject *
5548 clutter_actor_constructor (GType gtype,
5549                            guint n_props,
5550                            GObjectConstructParam *props)
5551 {
5552   GObjectClass *gobject_class;
5553   ClutterActor *self;
5554   GObject *retval;
5555
5556   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5557   retval = gobject_class->constructor (gtype, n_props, props);
5558   self = CLUTTER_ACTOR (retval);
5559
5560   if (self->priv->layout_manager == NULL)
5561     {
5562       ClutterLayoutManager *default_layout;
5563
5564       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5565
5566       default_layout = clutter_fixed_layout_new ();
5567       clutter_actor_set_layout_manager (self, default_layout);
5568     }
5569
5570   return retval;
5571 }
5572
5573 static void
5574 clutter_actor_class_init (ClutterActorClass *klass)
5575 {
5576   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5577
5578   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5579   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5580   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5581   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5582
5583   object_class->constructor = clutter_actor_constructor;
5584   object_class->set_property = clutter_actor_set_property;
5585   object_class->get_property = clutter_actor_get_property;
5586   object_class->dispose = clutter_actor_dispose;
5587   object_class->finalize = clutter_actor_finalize;
5588
5589   klass->show = clutter_actor_real_show;
5590   klass->show_all = clutter_actor_show;
5591   klass->hide = clutter_actor_real_hide;
5592   klass->hide_all = clutter_actor_hide;
5593   klass->map = clutter_actor_real_map;
5594   klass->unmap = clutter_actor_real_unmap;
5595   klass->unrealize = clutter_actor_real_unrealize;
5596   klass->pick = clutter_actor_real_pick;
5597   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5598   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5599   klass->allocate = clutter_actor_real_allocate;
5600   klass->queue_redraw = clutter_actor_real_queue_redraw;
5601   klass->queue_relayout = clutter_actor_real_queue_relayout;
5602   klass->apply_transform = clutter_actor_real_apply_transform;
5603   klass->get_accessible = clutter_actor_real_get_accessible;
5604   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5605   klass->has_overlaps = clutter_actor_real_has_overlaps;
5606   klass->paint = clutter_actor_real_paint;
5607   klass->destroy = clutter_actor_real_destroy;
5608
5609   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5610
5611   /**
5612    * ClutterActor:x:
5613    *
5614    * X coordinate of the actor in pixels. If written, forces a fixed
5615    * position for the actor. If read, returns the fixed position if any,
5616    * otherwise the allocation if available, otherwise 0.
5617    *
5618    * The #ClutterActor:x property is animatable.
5619    */
5620   obj_props[PROP_X] =
5621     g_param_spec_float ("x",
5622                         P_("X coordinate"),
5623                         P_("X coordinate of the actor"),
5624                         -G_MAXFLOAT, G_MAXFLOAT,
5625                         0.0,
5626                         G_PARAM_READWRITE |
5627                         G_PARAM_STATIC_STRINGS |
5628                         CLUTTER_PARAM_ANIMATABLE);
5629
5630   /**
5631    * ClutterActor:y:
5632    *
5633    * Y coordinate of the actor in pixels. If written, forces a fixed
5634    * position for the actor.  If read, returns the fixed position if
5635    * any, otherwise the allocation if available, otherwise 0.
5636    *
5637    * The #ClutterActor:y property is animatable.
5638    */
5639   obj_props[PROP_Y] =
5640     g_param_spec_float ("y",
5641                         P_("Y coordinate"),
5642                         P_("Y coordinate of the actor"),
5643                         -G_MAXFLOAT, G_MAXFLOAT,
5644                         0.0,
5645                         G_PARAM_READWRITE |
5646                         G_PARAM_STATIC_STRINGS |
5647                         CLUTTER_PARAM_ANIMATABLE);
5648
5649   /**
5650    * ClutterActor:position:
5651    *
5652    * The position of the origin of the actor.
5653    *
5654    * This property is a shorthand for setting and getting the
5655    * #ClutterActor:x and #ClutterActor:y properties at the same
5656    * time.
5657    *
5658    * The #ClutterActor:position property is animatable.
5659    *
5660    * Since: 1.12
5661    */
5662   obj_props[PROP_POSITION] =
5663     g_param_spec_boxed ("position",
5664                         P_("Position"),
5665                         P_("The position of the origin of the actor"),
5666                         CLUTTER_TYPE_POINT,
5667                         G_PARAM_READWRITE |
5668                         G_PARAM_STATIC_STRINGS |
5669                         CLUTTER_PARAM_ANIMATABLE);
5670
5671   /**
5672    * ClutterActor:width:
5673    *
5674    * Width of the actor (in pixels). If written, forces the minimum and
5675    * natural size request of the actor to the given width. If read, returns
5676    * the allocated width if available, otherwise the width request.
5677    *
5678    * The #ClutterActor:width property is animatable.
5679    */
5680   obj_props[PROP_WIDTH] =
5681     g_param_spec_float ("width",
5682                         P_("Width"),
5683                         P_("Width of the actor"),
5684                         0.0, G_MAXFLOAT,
5685                         0.0,
5686                         G_PARAM_READWRITE |
5687                         G_PARAM_STATIC_STRINGS |
5688                         CLUTTER_PARAM_ANIMATABLE);
5689
5690   /**
5691    * ClutterActor:height:
5692    *
5693    * Height of the actor (in pixels).  If written, forces the minimum and
5694    * natural size request of the actor to the given height. If read, returns
5695    * the allocated height if available, otherwise the height request.
5696    *
5697    * The #ClutterActor:height property is animatable.
5698    */
5699   obj_props[PROP_HEIGHT] =
5700     g_param_spec_float ("height",
5701                         P_("Height"),
5702                         P_("Height of the actor"),
5703                         0.0, G_MAXFLOAT,
5704                         0.0,
5705                         G_PARAM_READWRITE |
5706                         G_PARAM_STATIC_STRINGS |
5707                         CLUTTER_PARAM_ANIMATABLE);
5708
5709   /**
5710    * ClutterActor:size:
5711    *
5712    * The size of the actor.
5713    *
5714    * This property is a shorthand for setting and getting the
5715    * #ClutterActor:width and #ClutterActor:height at the same time.
5716    *
5717    * The #ClutterActor:size property is animatable.
5718    *
5719    * Since: 1.12
5720    */
5721   obj_props[PROP_SIZE] =
5722     g_param_spec_boxed ("size",
5723                         P_("Size"),
5724                         P_("The size of the actor"),
5725                         CLUTTER_TYPE_SIZE,
5726                         G_PARAM_READWRITE |
5727                         G_PARAM_STATIC_STRINGS |
5728                         CLUTTER_PARAM_ANIMATABLE);
5729
5730   /**
5731    * ClutterActor:fixed-x:
5732    *
5733    * The fixed X position of the actor in pixels.
5734    *
5735    * Writing this property sets #ClutterActor:fixed-position-set
5736    * property as well, as a side effect
5737    *
5738    * Since: 0.8
5739    */
5740   obj_props[PROP_FIXED_X] =
5741     g_param_spec_float ("fixed-x",
5742                         P_("Fixed X"),
5743                         P_("Forced X position of the actor"),
5744                         -G_MAXFLOAT, G_MAXFLOAT,
5745                         0.0,
5746                         CLUTTER_PARAM_READWRITE);
5747
5748   /**
5749    * ClutterActor:fixed-y:
5750    *
5751    * The fixed Y position of the actor in pixels.
5752    *
5753    * Writing this property sets the #ClutterActor:fixed-position-set
5754    * property as well, as a side effect
5755    *
5756    * Since: 0.8
5757    */
5758   obj_props[PROP_FIXED_Y] =
5759     g_param_spec_float ("fixed-y",
5760                         P_("Fixed Y"),
5761                         P_("Forced Y position of the actor"),
5762                         -G_MAXFLOAT, G_MAXFLOAT,
5763                         0,
5764                         CLUTTER_PARAM_READWRITE);
5765
5766   /**
5767    * ClutterActor:fixed-position-set:
5768    *
5769    * This flag controls whether the #ClutterActor:fixed-x and
5770    * #ClutterActor:fixed-y properties are used
5771    *
5772    * Since: 0.8
5773    */
5774   obj_props[PROP_FIXED_POSITION_SET] =
5775     g_param_spec_boolean ("fixed-position-set",
5776                           P_("Fixed position set"),
5777                           P_("Whether to use fixed positioning for the actor"),
5778                           FALSE,
5779                           CLUTTER_PARAM_READWRITE);
5780
5781   /**
5782    * ClutterActor:min-width:
5783    *
5784    * A forced minimum width request for the actor, in pixels
5785    *
5786    * Writing this property sets the #ClutterActor:min-width-set property
5787    * as well, as a side effect.
5788    *
5789    *This property overrides the usual width request of the actor.
5790    *
5791    * Since: 0.8
5792    */
5793   obj_props[PROP_MIN_WIDTH] =
5794     g_param_spec_float ("min-width",
5795                         P_("Min Width"),
5796                         P_("Forced minimum width request for the actor"),
5797                         0.0, G_MAXFLOAT,
5798                         0.0,
5799                         CLUTTER_PARAM_READWRITE);
5800
5801   /**
5802    * ClutterActor:min-height:
5803    *
5804    * A forced minimum height request for the actor, in pixels
5805    *
5806    * Writing this property sets the #ClutterActor:min-height-set property
5807    * as well, as a side effect. This property overrides the usual height
5808    * request of the actor.
5809    *
5810    * Since: 0.8
5811    */
5812   obj_props[PROP_MIN_HEIGHT] =
5813     g_param_spec_float ("min-height",
5814                         P_("Min Height"),
5815                         P_("Forced minimum height request for the actor"),
5816                         0.0, G_MAXFLOAT,
5817                         0.0,
5818                         CLUTTER_PARAM_READWRITE);
5819
5820   /**
5821    * ClutterActor:natural-width:
5822    *
5823    * A forced natural width request for the actor, in pixels
5824    *
5825    * Writing this property sets the #ClutterActor:natural-width-set
5826    * property as well, as a side effect. This property overrides the
5827    * usual width request of the actor
5828    *
5829    * Since: 0.8
5830    */
5831   obj_props[PROP_NATURAL_WIDTH] =
5832     g_param_spec_float ("natural-width",
5833                         P_("Natural Width"),
5834                         P_("Forced natural width request for the actor"),
5835                         0.0, G_MAXFLOAT,
5836                         0.0,
5837                         CLUTTER_PARAM_READWRITE);
5838
5839   /**
5840    * ClutterActor:natural-height:
5841    *
5842    * A forced natural height request for the actor, in pixels
5843    *
5844    * Writing this property sets the #ClutterActor:natural-height-set
5845    * property as well, as a side effect. This property overrides the
5846    * usual height request of the actor
5847    *
5848    * Since: 0.8
5849    */
5850   obj_props[PROP_NATURAL_HEIGHT] =
5851     g_param_spec_float ("natural-height",
5852                         P_("Natural Height"),
5853                         P_("Forced natural height request for the actor"),
5854                         0.0, G_MAXFLOAT,
5855                         0.0,
5856                         CLUTTER_PARAM_READWRITE);
5857
5858   /**
5859    * ClutterActor:min-width-set:
5860    *
5861    * This flag controls whether the #ClutterActor:min-width property
5862    * is used
5863    *
5864    * Since: 0.8
5865    */
5866   obj_props[PROP_MIN_WIDTH_SET] =
5867     g_param_spec_boolean ("min-width-set",
5868                           P_("Minimum width set"),
5869                           P_("Whether to use the min-width property"),
5870                           FALSE,
5871                           CLUTTER_PARAM_READWRITE);
5872
5873   /**
5874    * ClutterActor:min-height-set:
5875    *
5876    * This flag controls whether the #ClutterActor:min-height property
5877    * is used
5878    *
5879    * Since: 0.8
5880    */
5881   obj_props[PROP_MIN_HEIGHT_SET] =
5882     g_param_spec_boolean ("min-height-set",
5883                           P_("Minimum height set"),
5884                           P_("Whether to use the min-height property"),
5885                           FALSE,
5886                           CLUTTER_PARAM_READWRITE);
5887
5888   /**
5889    * ClutterActor:natural-width-set:
5890    *
5891    * This flag controls whether the #ClutterActor:natural-width property
5892    * is used
5893    *
5894    * Since: 0.8
5895    */
5896   obj_props[PROP_NATURAL_WIDTH_SET] =
5897     g_param_spec_boolean ("natural-width-set",
5898                           P_("Natural width set"),
5899                           P_("Whether to use the natural-width property"),
5900                           FALSE,
5901                           CLUTTER_PARAM_READWRITE);
5902
5903   /**
5904    * ClutterActor:natural-height-set:
5905    *
5906    * This flag controls whether the #ClutterActor:natural-height property
5907    * is used
5908    *
5909    * Since: 0.8
5910    */
5911   obj_props[PROP_NATURAL_HEIGHT_SET] =
5912     g_param_spec_boolean ("natural-height-set",
5913                           P_("Natural height set"),
5914                           P_("Whether to use the natural-height property"),
5915                           FALSE,
5916                           CLUTTER_PARAM_READWRITE);
5917
5918   /**
5919    * ClutterActor:allocation:
5920    *
5921    * The allocation for the actor, in pixels
5922    *
5923    * This is property is read-only, but you might monitor it to know when an
5924    * actor moves or resizes
5925    *
5926    * Since: 0.8
5927    */
5928   obj_props[PROP_ALLOCATION] =
5929     g_param_spec_boxed ("allocation",
5930                         P_("Allocation"),
5931                         P_("The actor's allocation"),
5932                         CLUTTER_TYPE_ACTOR_BOX,
5933                         G_PARAM_READABLE |
5934                         G_PARAM_STATIC_STRINGS |
5935                         CLUTTER_PARAM_ANIMATABLE);
5936
5937   /**
5938    * ClutterActor:request-mode:
5939    *
5940    * Request mode for the #ClutterActor. The request mode determines the
5941    * type of geometry management used by the actor, either height for width
5942    * (the default) or width for height.
5943    *
5944    * For actors implementing height for width, the parent container should get
5945    * the preferred width first, and then the preferred height for that width.
5946    *
5947    * For actors implementing width for height, the parent container should get
5948    * the preferred height first, and then the preferred width for that height.
5949    *
5950    * For instance:
5951    *
5952    * |[
5953    *   ClutterRequestMode mode;
5954    *   gfloat natural_width, min_width;
5955    *   gfloat natural_height, min_height;
5956    *
5957    *   mode = clutter_actor_get_request_mode (child);
5958    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5959    *     {
5960    *       clutter_actor_get_preferred_width (child, -1,
5961    *                                          &amp;min_width,
5962    *                                          &amp;natural_width);
5963    *       clutter_actor_get_preferred_height (child, natural_width,
5964    *                                           &amp;min_height,
5965    *                                           &amp;natural_height);
5966    *     }
5967    *   else
5968    *     {
5969    *       clutter_actor_get_preferred_height (child, -1,
5970    *                                           &amp;min_height,
5971    *                                           &amp;natural_height);
5972    *       clutter_actor_get_preferred_width (child, natural_height,
5973    *                                          &amp;min_width,
5974    *                                          &amp;natural_width);
5975    *     }
5976    * ]|
5977    *
5978    * will retrieve the minimum and natural width and height depending on the
5979    * preferred request mode of the #ClutterActor "child".
5980    *
5981    * The clutter_actor_get_preferred_size() function will implement this
5982    * check for you.
5983    *
5984    * Since: 0.8
5985    */
5986   obj_props[PROP_REQUEST_MODE] =
5987     g_param_spec_enum ("request-mode",
5988                        P_("Request Mode"),
5989                        P_("The actor's request mode"),
5990                        CLUTTER_TYPE_REQUEST_MODE,
5991                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5992                        CLUTTER_PARAM_READWRITE);
5993
5994   /**
5995    * ClutterActor:depth:
5996    *
5997    * The position of the actor on the Z axis.
5998    *
5999    * The #ClutterActor:depth property is relative to the parent's
6000    * modelview matrix.
6001    *
6002    * The #ClutterActor:depth property is animatable.
6003    *
6004    * Since: 0.6
6005    */
6006   obj_props[PROP_DEPTH] =
6007     g_param_spec_float ("depth",
6008                         P_("Depth"),
6009                         P_("Position on the Z axis"),
6010                         -G_MAXFLOAT, G_MAXFLOAT,
6011                         0.0,
6012                         G_PARAM_READWRITE |
6013                         G_PARAM_STATIC_STRINGS |
6014                         CLUTTER_PARAM_ANIMATABLE);
6015
6016   /**
6017    * ClutterActor:opacity:
6018    *
6019    * Opacity of an actor, between 0 (fully transparent) and
6020    * 255 (fully opaque)
6021    *
6022    * The #ClutterActor:opacity property is animatable.
6023    */
6024   obj_props[PROP_OPACITY] =
6025     g_param_spec_uint ("opacity",
6026                        P_("Opacity"),
6027                        P_("Opacity of an actor"),
6028                        0, 255,
6029                        255,
6030                        G_PARAM_READWRITE |
6031                        G_PARAM_STATIC_STRINGS |
6032                        CLUTTER_PARAM_ANIMATABLE);
6033
6034   /**
6035    * ClutterActor:offscreen-redirect:
6036    *
6037    * Determines the conditions in which the actor will be redirected
6038    * to an offscreen framebuffer while being painted. For example this
6039    * can be used to cache an actor in a framebuffer or for improved
6040    * handling of transparent actors. See
6041    * clutter_actor_set_offscreen_redirect() for details.
6042    *
6043    * Since: 1.8
6044    */
6045   obj_props[PROP_OFFSCREEN_REDIRECT] =
6046     g_param_spec_flags ("offscreen-redirect",
6047                         P_("Offscreen redirect"),
6048                         P_("Flags controlling when to flatten the actor into a single image"),
6049                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
6050                         0,
6051                         CLUTTER_PARAM_READWRITE);
6052
6053   /**
6054    * ClutterActor:visible:
6055    *
6056    * Whether the actor is set to be visible or not
6057    *
6058    * See also #ClutterActor:mapped
6059    */
6060   obj_props[PROP_VISIBLE] =
6061     g_param_spec_boolean ("visible",
6062                           P_("Visible"),
6063                           P_("Whether the actor is visible or not"),
6064                           FALSE,
6065                           CLUTTER_PARAM_READWRITE);
6066
6067   /**
6068    * ClutterActor:mapped:
6069    *
6070    * Whether the actor is mapped (will be painted when the stage
6071    * to which it belongs is mapped)
6072    *
6073    * Since: 1.0
6074    */
6075   obj_props[PROP_MAPPED] =
6076     g_param_spec_boolean ("mapped",
6077                           P_("Mapped"),
6078                           P_("Whether the actor will be painted"),
6079                           FALSE,
6080                           CLUTTER_PARAM_READABLE);
6081
6082   /**
6083    * ClutterActor:realized:
6084    *
6085    * Whether the actor has been realized
6086    *
6087    * Since: 1.0
6088    */
6089   obj_props[PROP_REALIZED] =
6090     g_param_spec_boolean ("realized",
6091                           P_("Realized"),
6092                           P_("Whether the actor has been realized"),
6093                           FALSE,
6094                           CLUTTER_PARAM_READABLE);
6095
6096   /**
6097    * ClutterActor:reactive:
6098    *
6099    * Whether the actor is reactive to events or not
6100    *
6101    * Only reactive actors will emit event-related signals
6102    *
6103    * Since: 0.6
6104    */
6105   obj_props[PROP_REACTIVE] =
6106     g_param_spec_boolean ("reactive",
6107                           P_("Reactive"),
6108                           P_("Whether the actor is reactive to events"),
6109                           FALSE,
6110                           CLUTTER_PARAM_READWRITE);
6111
6112   /**
6113    * ClutterActor:has-clip:
6114    *
6115    * Whether the actor has the #ClutterActor:clip property set or not
6116    */
6117   obj_props[PROP_HAS_CLIP] =
6118     g_param_spec_boolean ("has-clip",
6119                           P_("Has Clip"),
6120                           P_("Whether the actor has a clip set"),
6121                           FALSE,
6122                           CLUTTER_PARAM_READABLE);
6123
6124   /**
6125    * ClutterActor:clip:
6126    *
6127    * The clip region for the actor, in actor-relative coordinates
6128    *
6129    * Every part of the actor outside the clip region will not be
6130    * painted
6131    */
6132   obj_props[PROP_CLIP] =
6133     g_param_spec_boxed ("clip",
6134                         P_("Clip"),
6135                         P_("The clip region for the actor"),
6136                         CLUTTER_TYPE_GEOMETRY,
6137                         CLUTTER_PARAM_READWRITE);
6138
6139   /**
6140    * ClutterActor:name:
6141    *
6142    * The name of the actor
6143    *
6144    * Since: 0.2
6145    */
6146   obj_props[PROP_NAME] =
6147     g_param_spec_string ("name",
6148                          P_("Name"),
6149                          P_("Name of the actor"),
6150                          NULL,
6151                          CLUTTER_PARAM_READWRITE);
6152
6153   /**
6154    * ClutterActor:scale-x:
6155    *
6156    * The horizontal scale of the actor.
6157    *
6158    * The #ClutterActor:scale-x property is animatable.
6159    *
6160    * Since: 0.6
6161    */
6162   obj_props[PROP_SCALE_X] =
6163     g_param_spec_double ("scale-x",
6164                          P_("Scale X"),
6165                          P_("Scale factor on the X axis"),
6166                          0.0, G_MAXDOUBLE,
6167                          1.0,
6168                          G_PARAM_READWRITE |
6169                          G_PARAM_STATIC_STRINGS |
6170                          CLUTTER_PARAM_ANIMATABLE);
6171
6172   /**
6173    * ClutterActor:scale-y:
6174    *
6175    * The vertical scale of the actor.
6176    *
6177    * The #ClutterActor:scale-y property is animatable.
6178    *
6179    * Since: 0.6
6180    */
6181   obj_props[PROP_SCALE_Y] =
6182     g_param_spec_double ("scale-y",
6183                          P_("Scale Y"),
6184                          P_("Scale factor on the Y axis"),
6185                          0.0, G_MAXDOUBLE,
6186                          1.0,
6187                          G_PARAM_READWRITE |
6188                          G_PARAM_STATIC_STRINGS |
6189                          CLUTTER_PARAM_ANIMATABLE);
6190
6191   /**
6192    * ClutterActor:scale-center-x:
6193    *
6194    * The horizontal center point for scaling
6195    *
6196    * Since: 1.0
6197    */
6198   obj_props[PROP_SCALE_CENTER_X] =
6199     g_param_spec_float ("scale-center-x",
6200                         P_("Scale Center X"),
6201                         P_("Horizontal scale center"),
6202                         -G_MAXFLOAT, G_MAXFLOAT,
6203                         0.0,
6204                         CLUTTER_PARAM_READWRITE);
6205
6206   /**
6207    * ClutterActor:scale-center-y:
6208    *
6209    * The vertical center point for scaling
6210    *
6211    * Since: 1.0
6212    */
6213   obj_props[PROP_SCALE_CENTER_Y] =
6214     g_param_spec_float ("scale-center-y",
6215                         P_("Scale Center Y"),
6216                         P_("Vertical scale center"),
6217                         -G_MAXFLOAT, G_MAXFLOAT,
6218                         0.0,
6219                         CLUTTER_PARAM_READWRITE);
6220
6221   /**
6222    * ClutterActor:scale-gravity:
6223    *
6224    * The center point for scaling expressed as a #ClutterGravity
6225    *
6226    * Since: 1.0
6227    */
6228   obj_props[PROP_SCALE_GRAVITY] =
6229     g_param_spec_enum ("scale-gravity",
6230                        P_("Scale Gravity"),
6231                        P_("The center of scaling"),
6232                        CLUTTER_TYPE_GRAVITY,
6233                        CLUTTER_GRAVITY_NONE,
6234                        CLUTTER_PARAM_READWRITE);
6235
6236   /**
6237    * ClutterActor:rotation-angle-x:
6238    *
6239    * The rotation angle on the X axis.
6240    *
6241    * The #ClutterActor:rotation-angle-x property is animatable.
6242    *
6243    * Since: 0.6
6244    */
6245   obj_props[PROP_ROTATION_ANGLE_X] =
6246     g_param_spec_double ("rotation-angle-x",
6247                          P_("Rotation Angle X"),
6248                          P_("The rotation angle on the X axis"),
6249                          -G_MAXDOUBLE, G_MAXDOUBLE,
6250                          0.0,
6251                          G_PARAM_READWRITE |
6252                          G_PARAM_STATIC_STRINGS |
6253                          CLUTTER_PARAM_ANIMATABLE);
6254
6255   /**
6256    * ClutterActor:rotation-angle-y:
6257    *
6258    * The rotation angle on the Y axis
6259    *
6260    * The #ClutterActor:rotation-angle-y property is animatable.
6261    *
6262    * Since: 0.6
6263    */
6264   obj_props[PROP_ROTATION_ANGLE_Y] =
6265     g_param_spec_double ("rotation-angle-y",
6266                          P_("Rotation Angle Y"),
6267                          P_("The rotation angle on the Y axis"),
6268                          -G_MAXDOUBLE, G_MAXDOUBLE,
6269                          0.0,
6270                          G_PARAM_READWRITE |
6271                          G_PARAM_STATIC_STRINGS |
6272                          CLUTTER_PARAM_ANIMATABLE);
6273
6274   /**
6275    * ClutterActor:rotation-angle-z:
6276    *
6277    * The rotation angle on the Z axis
6278    *
6279    * The #ClutterActor:rotation-angle-z property is animatable.
6280    *
6281    * Since: 0.6
6282    */
6283   obj_props[PROP_ROTATION_ANGLE_Z] =
6284     g_param_spec_double ("rotation-angle-z",
6285                          P_("Rotation Angle Z"),
6286                          P_("The rotation angle on the Z axis"),
6287                          -G_MAXDOUBLE, G_MAXDOUBLE,
6288                          0.0,
6289                          G_PARAM_READWRITE |
6290                          G_PARAM_STATIC_STRINGS |
6291                          CLUTTER_PARAM_ANIMATABLE);
6292
6293   /**
6294    * ClutterActor:rotation-center-x:
6295    *
6296    * The rotation center on the X axis.
6297    *
6298    * Since: 0.6
6299    */
6300   obj_props[PROP_ROTATION_CENTER_X] =
6301     g_param_spec_boxed ("rotation-center-x",
6302                         P_("Rotation Center X"),
6303                         P_("The rotation center on the X axis"),
6304                         CLUTTER_TYPE_VERTEX,
6305                         CLUTTER_PARAM_READWRITE);
6306
6307   /**
6308    * ClutterActor:rotation-center-y:
6309    *
6310    * The rotation center on the Y axis.
6311    *
6312    * Since: 0.6
6313    */
6314   obj_props[PROP_ROTATION_CENTER_Y] =
6315     g_param_spec_boxed ("rotation-center-y",
6316                         P_("Rotation Center Y"),
6317                         P_("The rotation center on the Y axis"),
6318                         CLUTTER_TYPE_VERTEX,
6319                         CLUTTER_PARAM_READWRITE);
6320
6321   /**
6322    * ClutterActor:rotation-center-z:
6323    *
6324    * The rotation center on the Z axis.
6325    *
6326    * Since: 0.6
6327    */
6328   obj_props[PROP_ROTATION_CENTER_Z] =
6329     g_param_spec_boxed ("rotation-center-z",
6330                         P_("Rotation Center Z"),
6331                         P_("The rotation center on the Z axis"),
6332                         CLUTTER_TYPE_VERTEX,
6333                         CLUTTER_PARAM_READWRITE);
6334
6335   /**
6336    * ClutterActor:rotation-center-z-gravity:
6337    *
6338    * The rotation center on the Z axis expressed as a #ClutterGravity.
6339    *
6340    * Since: 1.0
6341    */
6342   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6343     g_param_spec_enum ("rotation-center-z-gravity",
6344                        P_("Rotation Center Z Gravity"),
6345                        P_("Center point for rotation around the Z axis"),
6346                        CLUTTER_TYPE_GRAVITY,
6347                        CLUTTER_GRAVITY_NONE,
6348                        CLUTTER_PARAM_READWRITE);
6349
6350   /**
6351    * ClutterActor:anchor-x:
6352    *
6353    * The X coordinate of an actor's anchor point, relative to
6354    * the actor coordinate space, in pixels
6355    *
6356    * Since: 0.8
6357    */
6358   obj_props[PROP_ANCHOR_X] =
6359     g_param_spec_float ("anchor-x",
6360                         P_("Anchor X"),
6361                         P_("X coordinate of the anchor point"),
6362                         -G_MAXFLOAT, G_MAXFLOAT,
6363                         0,
6364                         CLUTTER_PARAM_READWRITE);
6365
6366   /**
6367    * ClutterActor:anchor-y:
6368    *
6369    * The Y coordinate of an actor's anchor point, relative to
6370    * the actor coordinate space, in pixels
6371    *
6372    * Since: 0.8
6373    */
6374   obj_props[PROP_ANCHOR_Y] =
6375     g_param_spec_float ("anchor-y",
6376                         P_("Anchor Y"),
6377                         P_("Y coordinate of the anchor point"),
6378                         -G_MAXFLOAT, G_MAXFLOAT,
6379                         0,
6380                         CLUTTER_PARAM_READWRITE);
6381
6382   /**
6383    * ClutterActor:anchor-gravity:
6384    *
6385    * The anchor point expressed as a #ClutterGravity
6386    *
6387    * Since: 1.0
6388    */
6389   obj_props[PROP_ANCHOR_GRAVITY] =
6390     g_param_spec_enum ("anchor-gravity",
6391                        P_("Anchor Gravity"),
6392                        P_("The anchor point as a ClutterGravity"),
6393                        CLUTTER_TYPE_GRAVITY,
6394                        CLUTTER_GRAVITY_NONE,
6395                        CLUTTER_PARAM_READWRITE);
6396
6397   /**
6398    * ClutterActor:show-on-set-parent:
6399    *
6400    * If %TRUE, the actor is automatically shown when parented.
6401    *
6402    * Calling clutter_actor_hide() on an actor which has not been
6403    * parented will set this property to %FALSE as a side effect.
6404    *
6405    * Since: 0.8
6406    */
6407   obj_props[PROP_SHOW_ON_SET_PARENT] =
6408     g_param_spec_boolean ("show-on-set-parent",
6409                           P_("Show on set parent"),
6410                           P_("Whether the actor is shown when parented"),
6411                           TRUE,
6412                           CLUTTER_PARAM_READWRITE);
6413
6414   /**
6415    * ClutterActor:clip-to-allocation:
6416    *
6417    * Whether the clip region should track the allocated area
6418    * of the actor.
6419    *
6420    * This property is ignored if a clip area has been explicitly
6421    * set using clutter_actor_set_clip().
6422    *
6423    * Since: 1.0
6424    */
6425   obj_props[PROP_CLIP_TO_ALLOCATION] =
6426     g_param_spec_boolean ("clip-to-allocation",
6427                           P_("Clip to Allocation"),
6428                           P_("Sets the clip region to track the actor's allocation"),
6429                           FALSE,
6430                           CLUTTER_PARAM_READWRITE);
6431
6432   /**
6433    * ClutterActor:text-direction:
6434    *
6435    * The direction of the text inside a #ClutterActor.
6436    *
6437    * Since: 1.0
6438    */
6439   obj_props[PROP_TEXT_DIRECTION] =
6440     g_param_spec_enum ("text-direction",
6441                        P_("Text Direction"),
6442                        P_("Direction of the text"),
6443                        CLUTTER_TYPE_TEXT_DIRECTION,
6444                        CLUTTER_TEXT_DIRECTION_LTR,
6445                        CLUTTER_PARAM_READWRITE);
6446
6447   /**
6448    * ClutterActor:has-pointer:
6449    *
6450    * Whether the actor contains the pointer of a #ClutterInputDevice
6451    * or not.
6452    *
6453    * Since: 1.2
6454    */
6455   obj_props[PROP_HAS_POINTER] =
6456     g_param_spec_boolean ("has-pointer",
6457                           P_("Has Pointer"),
6458                           P_("Whether the actor contains the pointer of an input device"),
6459                           FALSE,
6460                           CLUTTER_PARAM_READABLE);
6461
6462   /**
6463    * ClutterActor:actions:
6464    *
6465    * Adds a #ClutterAction to the actor
6466    *
6467    * Since: 1.4
6468    */
6469   obj_props[PROP_ACTIONS] =
6470     g_param_spec_object ("actions",
6471                          P_("Actions"),
6472                          P_("Adds an action to the actor"),
6473                          CLUTTER_TYPE_ACTION,
6474                          CLUTTER_PARAM_WRITABLE);
6475
6476   /**
6477    * ClutterActor:constraints:
6478    *
6479    * Adds a #ClutterConstraint to the actor
6480    *
6481    * Since: 1.4
6482    */
6483   obj_props[PROP_CONSTRAINTS] =
6484     g_param_spec_object ("constraints",
6485                          P_("Constraints"),
6486                          P_("Adds a constraint to the actor"),
6487                          CLUTTER_TYPE_CONSTRAINT,
6488                          CLUTTER_PARAM_WRITABLE);
6489
6490   /**
6491    * ClutterActor:effect:
6492    *
6493    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6494    *
6495    * Since: 1.4
6496    */
6497   obj_props[PROP_EFFECT] =
6498     g_param_spec_object ("effect",
6499                          P_("Effect"),
6500                          P_("Add an effect to be applied on the actor"),
6501                          CLUTTER_TYPE_EFFECT,
6502                          CLUTTER_PARAM_WRITABLE);
6503
6504   /**
6505    * ClutterActor:layout-manager:
6506    *
6507    * A delegate object for controlling the layout of the children of
6508    * an actor.
6509    *
6510    * Since: 1.10
6511    */
6512   obj_props[PROP_LAYOUT_MANAGER] =
6513     g_param_spec_object ("layout-manager",
6514                          P_("Layout Manager"),
6515                          P_("The object controlling the layout of an actor's children"),
6516                          CLUTTER_TYPE_LAYOUT_MANAGER,
6517                          CLUTTER_PARAM_READWRITE);
6518
6519   /**
6520    * ClutterActor:x-expand:
6521    *
6522    * Whether a layout manager should assign more space to the actor on
6523    * the X axis.
6524    *
6525    * Since: 1.12
6526    */
6527   obj_props[PROP_X_EXPAND] =
6528     g_param_spec_boolean ("x-expand",
6529                           P_("X Expand"),
6530                           P_("Whether extra horizontal space should be assigned to the actor"),
6531                           FALSE,
6532                           G_PARAM_READWRITE |
6533                           G_PARAM_STATIC_STRINGS);
6534
6535   /**
6536    * ClutterActor:y-expand:
6537    *
6538    * Whether a layout manager should assign more space to the actor on
6539    * the Y axis.
6540    *
6541    * Since: 1.12
6542    */
6543   obj_props[PROP_Y_EXPAND] =
6544     g_param_spec_boolean ("y-expand",
6545                           P_("Y Expand"),
6546                           P_("Whether extra vertical space should be assigned to the actor"),
6547                           FALSE,
6548                           G_PARAM_READWRITE |
6549                           G_PARAM_STATIC_STRINGS);
6550
6551   /**
6552    * ClutterActor:x-align:
6553    *
6554    * The alignment of an actor on the X axis, if the actor has been given
6555    * extra space for its allocation. See also the #ClutterActor:x-expand
6556    * property.
6557    *
6558    * Since: 1.10
6559    */
6560   obj_props[PROP_X_ALIGN] =
6561     g_param_spec_enum ("x-align",
6562                        P_("X Alignment"),
6563                        P_("The alignment of the actor on the X axis within its allocation"),
6564                        CLUTTER_TYPE_ACTOR_ALIGN,
6565                        CLUTTER_ACTOR_ALIGN_FILL,
6566                        CLUTTER_PARAM_READWRITE);
6567
6568   /**
6569    * ClutterActor:y-align:
6570    *
6571    * The alignment of an actor on the Y axis, if the actor has been given
6572    * extra space for its allocation.
6573    *
6574    * Since: 1.10
6575    */
6576   obj_props[PROP_Y_ALIGN] =
6577     g_param_spec_enum ("y-align",
6578                        P_("Y Alignment"),
6579                        P_("The alignment of the actor on the Y axis within its allocation"),
6580                        CLUTTER_TYPE_ACTOR_ALIGN,
6581                        CLUTTER_ACTOR_ALIGN_FILL,
6582                        CLUTTER_PARAM_READWRITE);
6583
6584   /**
6585    * ClutterActor:margin-top:
6586    *
6587    * The margin (in pixels) from the top of the actor.
6588    *
6589    * This property adds a margin to the actor's preferred size; the margin
6590    * will be automatically taken into account when allocating the actor.
6591    *
6592    * Since: 1.10
6593    */
6594   obj_props[PROP_MARGIN_TOP] =
6595     g_param_spec_float ("margin-top",
6596                         P_("Margin Top"),
6597                         P_("Extra space at the top"),
6598                         0.0, G_MAXFLOAT,
6599                         0.0,
6600                         CLUTTER_PARAM_READWRITE);
6601
6602   /**
6603    * ClutterActor:margin-bottom:
6604    *
6605    * The margin (in pixels) from the bottom of the actor.
6606    *
6607    * This property adds a margin to the actor's preferred size; the margin
6608    * will be automatically taken into account when allocating the actor.
6609    *
6610    * Since: 1.10
6611    */
6612   obj_props[PROP_MARGIN_BOTTOM] =
6613     g_param_spec_float ("margin-bottom",
6614                         P_("Margin Bottom"),
6615                         P_("Extra space at the bottom"),
6616                         0.0, G_MAXFLOAT,
6617                         0.0,
6618                         CLUTTER_PARAM_READWRITE);
6619
6620   /**
6621    * ClutterActor:margin-left:
6622    *
6623    * The margin (in pixels) from the left of the actor.
6624    *
6625    * This property adds a margin to the actor's preferred size; the margin
6626    * will be automatically taken into account when allocating the actor.
6627    *
6628    * Since: 1.10
6629    */
6630   obj_props[PROP_MARGIN_LEFT] =
6631     g_param_spec_float ("margin-left",
6632                         P_("Margin Left"),
6633                         P_("Extra space at the left"),
6634                         0.0, G_MAXFLOAT,
6635                         0.0,
6636                         CLUTTER_PARAM_READWRITE);
6637
6638   /**
6639    * ClutterActor:margin-right:
6640    *
6641    * The margin (in pixels) from the right of the actor.
6642    *
6643    * This property adds a margin to the actor's preferred size; the margin
6644    * will be automatically taken into account when allocating the actor.
6645    *
6646    * Since: 1.10
6647    */
6648   obj_props[PROP_MARGIN_RIGHT] =
6649     g_param_spec_float ("margin-right",
6650                         P_("Margin Right"),
6651                         P_("Extra space at the right"),
6652                         0.0, G_MAXFLOAT,
6653                         0.0,
6654                         CLUTTER_PARAM_READWRITE);
6655
6656   /**
6657    * ClutterActor:background-color-set:
6658    *
6659    * Whether the #ClutterActor:background-color property has been set.
6660    *
6661    * Since: 1.10
6662    */
6663   obj_props[PROP_BACKGROUND_COLOR_SET] =
6664     g_param_spec_boolean ("background-color-set",
6665                           P_("Background Color Set"),
6666                           P_("Whether the background color is set"),
6667                           FALSE,
6668                           CLUTTER_PARAM_READABLE);
6669
6670   /**
6671    * ClutterActor:background-color:
6672    *
6673    * Paints a solid fill of the actor's allocation using the specified
6674    * color.
6675    *
6676    * The #ClutterActor:background-color property is animatable.
6677    *
6678    * Since: 1.10
6679    */
6680   obj_props[PROP_BACKGROUND_COLOR] =
6681     clutter_param_spec_color ("background-color",
6682                               P_("Background color"),
6683                               P_("The actor's background color"),
6684                               CLUTTER_COLOR_Transparent,
6685                               G_PARAM_READWRITE |
6686                               G_PARAM_STATIC_STRINGS |
6687                               CLUTTER_PARAM_ANIMATABLE);
6688
6689   /**
6690    * ClutterActor:first-child:
6691    *
6692    * The actor's first child.
6693    *
6694    * Since: 1.10
6695    */
6696   obj_props[PROP_FIRST_CHILD] =
6697     g_param_spec_object ("first-child",
6698                          P_("First Child"),
6699                          P_("The actor's first child"),
6700                          CLUTTER_TYPE_ACTOR,
6701                          CLUTTER_PARAM_READABLE);
6702
6703   /**
6704    * ClutterActor:last-child:
6705    *
6706    * The actor's last child.
6707    *
6708    * Since: 1.10
6709    */
6710   obj_props[PROP_LAST_CHILD] =
6711     g_param_spec_object ("last-child",
6712                          P_("Last Child"),
6713                          P_("The actor's last child"),
6714                          CLUTTER_TYPE_ACTOR,
6715                          CLUTTER_PARAM_READABLE);
6716
6717   /**
6718    * ClutterActor:content:
6719    *
6720    * The #ClutterContent implementation that controls the content
6721    * of the actor.
6722    *
6723    * Since: 1.10
6724    */
6725   obj_props[PROP_CONTENT] =
6726     g_param_spec_object ("content",
6727                          P_("Content"),
6728                          P_("Delegate object for painting the actor's content"),
6729                          CLUTTER_TYPE_CONTENT,
6730                          CLUTTER_PARAM_READWRITE);
6731
6732   /**
6733    * ClutterActor:content-gravity:
6734    *
6735    * The alignment that should be honoured by the #ClutterContent
6736    * set with the #ClutterActor:content property.
6737    *
6738    * Changing the value of this property will change the bounding box of
6739    * the content; you can use the #ClutterActor:content-box property to
6740    * get the position and size of the content within the actor's
6741    * allocation.
6742    *
6743    * This property is meaningful only for #ClutterContent implementations
6744    * that have a preferred size, and if the preferred size is smaller than
6745    * the actor's allocation.
6746    *
6747    * The #ClutterActor:content-gravity property is animatable.
6748    *
6749    * Since: 1.10
6750    */
6751   obj_props[PROP_CONTENT_GRAVITY] =
6752     g_param_spec_enum ("content-gravity",
6753                        P_("Content Gravity"),
6754                        P_("Alignment of the actor's content"),
6755                        CLUTTER_TYPE_CONTENT_GRAVITY,
6756                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6757                        CLUTTER_PARAM_READWRITE);
6758
6759   /**
6760    * ClutterActor:content-box:
6761    *
6762    * The bounding box for the #ClutterContent used by the actor.
6763    *
6764    * The value of this property is controlled by the #ClutterActor:allocation
6765    * and #ClutterActor:content-gravity properties of #ClutterActor.
6766    *
6767    * The bounding box for the content is guaranteed to never exceed the
6768    * allocation's of the actor.
6769    *
6770    * Since: 1.10
6771    */
6772   obj_props[PROP_CONTENT_BOX] =
6773     g_param_spec_boxed ("content-box",
6774                         P_("Content Box"),
6775                         P_("The bounding box of the actor's content"),
6776                         CLUTTER_TYPE_ACTOR_BOX,
6777                         G_PARAM_READABLE |
6778                         G_PARAM_STATIC_STRINGS |
6779                         CLUTTER_PARAM_ANIMATABLE);
6780
6781   obj_props[PROP_MINIFICATION_FILTER] =
6782     g_param_spec_enum ("minification-filter",
6783                        P_("Minification Filter"),
6784                        P_("The filter used when reducing the size of the content"),
6785                        CLUTTER_TYPE_SCALING_FILTER,
6786                        CLUTTER_SCALING_FILTER_LINEAR,
6787                        CLUTTER_PARAM_READWRITE);
6788
6789   obj_props[PROP_MAGNIFICATION_FILTER] =
6790     g_param_spec_enum ("magnification-filter",
6791                        P_("Magnification Filter"),
6792                        P_("The filter used when increasing the size of the content"),
6793                        CLUTTER_TYPE_SCALING_FILTER,
6794                        CLUTTER_SCALING_FILTER_LINEAR,
6795                        CLUTTER_PARAM_READWRITE);
6796
6797   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6798
6799   /**
6800    * ClutterActor::destroy:
6801    * @actor: the #ClutterActor which emitted the signal
6802    *
6803    * The ::destroy signal notifies that all references held on the
6804    * actor which emitted it should be released.
6805    *
6806    * The ::destroy signal should be used by all holders of a reference
6807    * on @actor.
6808    *
6809    * This signal might result in the finalization of the #ClutterActor
6810    * if all references are released.
6811    *
6812    * Composite actors and actors implementing the #ClutterContainer
6813    * interface should override the default implementation of the
6814    * class handler of this signal and call clutter_actor_destroy() on
6815    * their children. When overriding the default class handler, it is
6816    * required to chain up to the parent's implementation.
6817    *
6818    * Since: 0.2
6819    */
6820   actor_signals[DESTROY] =
6821     g_signal_new (I_("destroy"),
6822                   G_TYPE_FROM_CLASS (object_class),
6823                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6824                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6825                   NULL, NULL,
6826                   _clutter_marshal_VOID__VOID,
6827                   G_TYPE_NONE, 0);
6828   /**
6829    * ClutterActor::show:
6830    * @actor: the object which received the signal
6831    *
6832    * The ::show signal is emitted when an actor is visible and
6833    * rendered on the stage.
6834    *
6835    * Since: 0.2
6836    */
6837   actor_signals[SHOW] =
6838     g_signal_new (I_("show"),
6839                   G_TYPE_FROM_CLASS (object_class),
6840                   G_SIGNAL_RUN_FIRST,
6841                   G_STRUCT_OFFSET (ClutterActorClass, show),
6842                   NULL, NULL,
6843                   _clutter_marshal_VOID__VOID,
6844                   G_TYPE_NONE, 0);
6845   /**
6846    * ClutterActor::hide:
6847    * @actor: the object which received the signal
6848    *
6849    * The ::hide signal is emitted when an actor is no longer rendered
6850    * on the stage.
6851    *
6852    * Since: 0.2
6853    */
6854   actor_signals[HIDE] =
6855     g_signal_new (I_("hide"),
6856                   G_TYPE_FROM_CLASS (object_class),
6857                   G_SIGNAL_RUN_FIRST,
6858                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6859                   NULL, NULL,
6860                   _clutter_marshal_VOID__VOID,
6861                   G_TYPE_NONE, 0);
6862   /**
6863    * ClutterActor::parent-set:
6864    * @actor: the object which received the signal
6865    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6866    *
6867    * This signal is emitted when the parent of the actor changes.
6868    *
6869    * Since: 0.2
6870    */
6871   actor_signals[PARENT_SET] =
6872     g_signal_new (I_("parent-set"),
6873                   G_TYPE_FROM_CLASS (object_class),
6874                   G_SIGNAL_RUN_LAST,
6875                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6876                   NULL, NULL,
6877                   _clutter_marshal_VOID__OBJECT,
6878                   G_TYPE_NONE, 1,
6879                   CLUTTER_TYPE_ACTOR);
6880
6881   /**
6882    * ClutterActor::queue-redraw:
6883    * @actor: the actor we're bubbling the redraw request through
6884    * @origin: the actor which initiated the redraw request
6885    *
6886    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6887    * is called on @origin.
6888    *
6889    * The default implementation for #ClutterActor chains up to the
6890    * parent actor and queues a redraw on the parent, thus "bubbling"
6891    * the redraw queue up through the actor graph. The default
6892    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6893    * in a main loop idle handler.
6894    *
6895    * Note that the @origin actor may be the stage, or a container; it
6896    * does not have to be a leaf node in the actor graph.
6897    *
6898    * Toolkits embedding a #ClutterStage which require a redraw and
6899    * relayout cycle can stop the emission of this signal using the
6900    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6901    * themselves, like:
6902    *
6903    * |[
6904    *   static void
6905    *   on_redraw_complete (gpointer data)
6906    *   {
6907    *     ClutterStage *stage = data;
6908    *
6909    *     /&ast; execute the Clutter drawing pipeline &ast;/
6910    *     clutter_stage_ensure_redraw (stage);
6911    *   }
6912    *
6913    *   static void
6914    *   on_stage_queue_redraw (ClutterStage *stage)
6915    *   {
6916    *     /&ast; this prevents the default handler to run &ast;/
6917    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6918    *
6919    *     /&ast; queue a redraw with the host toolkit and call
6920    *      &ast; a function when the redraw has been completed
6921    *      &ast;/
6922    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6923    *   }
6924    * ]|
6925    *
6926    * <note><para>This signal is emitted before the Clutter paint
6927    * pipeline is executed. If you want to know when the pipeline has
6928    * been completed you should connect to the ::paint signal on the
6929    * Stage with g_signal_connect_after().</para></note>
6930    *
6931    * Since: 1.0
6932    */
6933   actor_signals[QUEUE_REDRAW] =
6934     g_signal_new (I_("queue-redraw"),
6935                   G_TYPE_FROM_CLASS (object_class),
6936                   G_SIGNAL_RUN_LAST |
6937                   G_SIGNAL_NO_HOOKS,
6938                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6939                   NULL, NULL,
6940                   _clutter_marshal_VOID__OBJECT,
6941                   G_TYPE_NONE, 1,
6942                   CLUTTER_TYPE_ACTOR);
6943
6944   /**
6945    * ClutterActor::queue-relayout:
6946    * @actor: the actor being queued for relayout
6947    *
6948    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6949    * is called on an actor.
6950    *
6951    * The default implementation for #ClutterActor chains up to the
6952    * parent actor and queues a relayout on the parent, thus "bubbling"
6953    * the relayout queue up through the actor graph.
6954    *
6955    * The main purpose of this signal is to allow relayout to be propagated
6956    * properly in the procense of #ClutterClone actors. Applications will
6957    * not normally need to connect to this signal.
6958    *
6959    * Since: 1.2
6960    */
6961   actor_signals[QUEUE_RELAYOUT] =
6962     g_signal_new (I_("queue-relayout"),
6963                   G_TYPE_FROM_CLASS (object_class),
6964                   G_SIGNAL_RUN_LAST |
6965                   G_SIGNAL_NO_HOOKS,
6966                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6967                   NULL, NULL,
6968                   _clutter_marshal_VOID__VOID,
6969                   G_TYPE_NONE, 0);
6970
6971   /**
6972    * ClutterActor::event:
6973    * @actor: the actor which received the event
6974    * @event: a #ClutterEvent
6975    *
6976    * The ::event signal is emitted each time an event is received
6977    * by the @actor. This signal will be emitted on every actor,
6978    * following the hierarchy chain, until it reaches the top-level
6979    * container (the #ClutterStage).
6980    *
6981    * Return value: %TRUE if the event has been handled by the actor,
6982    *   or %FALSE to continue the emission.
6983    *
6984    * Since: 0.6
6985    */
6986   actor_signals[EVENT] =
6987     g_signal_new (I_("event"),
6988                   G_TYPE_FROM_CLASS (object_class),
6989                   G_SIGNAL_RUN_LAST,
6990                   G_STRUCT_OFFSET (ClutterActorClass, event),
6991                   _clutter_boolean_handled_accumulator, NULL,
6992                   _clutter_marshal_BOOLEAN__BOXED,
6993                   G_TYPE_BOOLEAN, 1,
6994                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6995   /**
6996    * ClutterActor::button-press-event:
6997    * @actor: the actor which received the event
6998    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6999    *
7000    * The ::button-press-event signal is emitted each time a mouse button
7001    * is pressed on @actor.
7002    *
7003    * Return value: %TRUE if the event has been handled by the actor,
7004    *   or %FALSE to continue the emission.
7005    *
7006    * Since: 0.6
7007    */
7008   actor_signals[BUTTON_PRESS_EVENT] =
7009     g_signal_new (I_("button-press-event"),
7010                   G_TYPE_FROM_CLASS (object_class),
7011                   G_SIGNAL_RUN_LAST,
7012                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
7013                   _clutter_boolean_handled_accumulator, NULL,
7014                   _clutter_marshal_BOOLEAN__BOXED,
7015                   G_TYPE_BOOLEAN, 1,
7016                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7017   /**
7018    * ClutterActor::button-release-event:
7019    * @actor: the actor which received the event
7020    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
7021    *
7022    * The ::button-release-event signal is emitted each time a mouse button
7023    * is released on @actor.
7024    *
7025    * Return value: %TRUE if the event has been handled by the actor,
7026    *   or %FALSE to continue the emission.
7027    *
7028    * Since: 0.6
7029    */
7030   actor_signals[BUTTON_RELEASE_EVENT] =
7031     g_signal_new (I_("button-release-event"),
7032                   G_TYPE_FROM_CLASS (object_class),
7033                   G_SIGNAL_RUN_LAST,
7034                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
7035                   _clutter_boolean_handled_accumulator, NULL,
7036                   _clutter_marshal_BOOLEAN__BOXED,
7037                   G_TYPE_BOOLEAN, 1,
7038                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7039   /**
7040    * ClutterActor::scroll-event:
7041    * @actor: the actor which received the event
7042    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
7043    *
7044    * The ::scroll-event signal is emitted each time the mouse is
7045    * scrolled on @actor
7046    *
7047    * Return value: %TRUE if the event has been handled by the actor,
7048    *   or %FALSE to continue the emission.
7049    *
7050    * Since: 0.6
7051    */
7052   actor_signals[SCROLL_EVENT] =
7053     g_signal_new (I_("scroll-event"),
7054                   G_TYPE_FROM_CLASS (object_class),
7055                   G_SIGNAL_RUN_LAST,
7056                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
7057                   _clutter_boolean_handled_accumulator, NULL,
7058                   _clutter_marshal_BOOLEAN__BOXED,
7059                   G_TYPE_BOOLEAN, 1,
7060                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7061   /**
7062    * ClutterActor::key-press-event:
7063    * @actor: the actor which received the event
7064    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7065    *
7066    * The ::key-press-event signal is emitted each time a keyboard button
7067    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
7068    *
7069    * Return value: %TRUE if the event has been handled by the actor,
7070    *   or %FALSE to continue the emission.
7071    *
7072    * Since: 0.6
7073    */
7074   actor_signals[KEY_PRESS_EVENT] =
7075     g_signal_new (I_("key-press-event"),
7076                   G_TYPE_FROM_CLASS (object_class),
7077                   G_SIGNAL_RUN_LAST,
7078                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
7079                   _clutter_boolean_handled_accumulator, NULL,
7080                   _clutter_marshal_BOOLEAN__BOXED,
7081                   G_TYPE_BOOLEAN, 1,
7082                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7083   /**
7084    * ClutterActor::key-release-event:
7085    * @actor: the actor which received the event
7086    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
7087    *
7088    * The ::key-release-event signal is emitted each time a keyboard button
7089    * is released while @actor has key focus (see
7090    * clutter_stage_set_key_focus()).
7091    *
7092    * Return value: %TRUE if the event has been handled by the actor,
7093    *   or %FALSE to continue the emission.
7094    *
7095    * Since: 0.6
7096    */
7097   actor_signals[KEY_RELEASE_EVENT] =
7098     g_signal_new (I_("key-release-event"),
7099                   G_TYPE_FROM_CLASS (object_class),
7100                   G_SIGNAL_RUN_LAST,
7101                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
7102                   _clutter_boolean_handled_accumulator, NULL,
7103                   _clutter_marshal_BOOLEAN__BOXED,
7104                   G_TYPE_BOOLEAN, 1,
7105                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7106   /**
7107    * ClutterActor::motion-event:
7108    * @actor: the actor which received the event
7109    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
7110    *
7111    * The ::motion-event signal is emitted each time the mouse pointer is
7112    * moved over @actor.
7113    *
7114    * Return value: %TRUE if the event has been handled by the actor,
7115    *   or %FALSE to continue the emission.
7116    *
7117    * Since: 0.6
7118    */
7119   actor_signals[MOTION_EVENT] =
7120     g_signal_new (I_("motion-event"),
7121                   G_TYPE_FROM_CLASS (object_class),
7122                   G_SIGNAL_RUN_LAST,
7123                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
7124                   _clutter_boolean_handled_accumulator, NULL,
7125                   _clutter_marshal_BOOLEAN__BOXED,
7126                   G_TYPE_BOOLEAN, 1,
7127                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7128
7129   /**
7130    * ClutterActor::key-focus-in:
7131    * @actor: the actor which now has key focus
7132    *
7133    * The ::key-focus-in signal is emitted when @actor receives key focus.
7134    *
7135    * Since: 0.6
7136    */
7137   actor_signals[KEY_FOCUS_IN] =
7138     g_signal_new (I_("key-focus-in"),
7139                   G_TYPE_FROM_CLASS (object_class),
7140                   G_SIGNAL_RUN_LAST,
7141                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
7142                   NULL, NULL,
7143                   _clutter_marshal_VOID__VOID,
7144                   G_TYPE_NONE, 0);
7145
7146   /**
7147    * ClutterActor::key-focus-out:
7148    * @actor: the actor which now has key focus
7149    *
7150    * The ::key-focus-out signal is emitted when @actor loses key focus.
7151    *
7152    * Since: 0.6
7153    */
7154   actor_signals[KEY_FOCUS_OUT] =
7155     g_signal_new (I_("key-focus-out"),
7156                   G_TYPE_FROM_CLASS (object_class),
7157                   G_SIGNAL_RUN_LAST,
7158                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
7159                   NULL, NULL,
7160                   _clutter_marshal_VOID__VOID,
7161                   G_TYPE_NONE, 0);
7162
7163   /**
7164    * ClutterActor::enter-event:
7165    * @actor: the actor which the pointer has entered.
7166    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7167    *
7168    * The ::enter-event signal is emitted when the pointer enters the @actor
7169    *
7170    * Return value: %TRUE if the event has been handled by the actor,
7171    *   or %FALSE to continue the emission.
7172    *
7173    * Since: 0.6
7174    */
7175   actor_signals[ENTER_EVENT] =
7176     g_signal_new (I_("enter-event"),
7177                   G_TYPE_FROM_CLASS (object_class),
7178                   G_SIGNAL_RUN_LAST,
7179                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
7180                   _clutter_boolean_handled_accumulator, NULL,
7181                   _clutter_marshal_BOOLEAN__BOXED,
7182                   G_TYPE_BOOLEAN, 1,
7183                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7184
7185   /**
7186    * ClutterActor::leave-event:
7187    * @actor: the actor which the pointer has left
7188    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7189    *
7190    * The ::leave-event signal is emitted when the pointer leaves the @actor.
7191    *
7192    * Return value: %TRUE if the event has been handled by the actor,
7193    *   or %FALSE to continue the emission.
7194    *
7195    * Since: 0.6
7196    */
7197   actor_signals[LEAVE_EVENT] =
7198     g_signal_new (I_("leave-event"),
7199                   G_TYPE_FROM_CLASS (object_class),
7200                   G_SIGNAL_RUN_LAST,
7201                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7202                   _clutter_boolean_handled_accumulator, NULL,
7203                   _clutter_marshal_BOOLEAN__BOXED,
7204                   G_TYPE_BOOLEAN, 1,
7205                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7206
7207   /**
7208    * ClutterActor::captured-event:
7209    * @actor: the actor which received the signal
7210    * @event: a #ClutterEvent
7211    *
7212    * The ::captured-event signal is emitted when an event is captured
7213    * by Clutter. This signal will be emitted starting from the top-level
7214    * container (the #ClutterStage) to the actor which received the event
7215    * going down the hierarchy. This signal can be used to intercept every
7216    * event before the specialized events (like
7217    * ClutterActor::button-press-event or ::key-released-event) are
7218    * emitted.
7219    *
7220    * Return value: %TRUE if the event has been handled by the actor,
7221    *   or %FALSE to continue the emission.
7222    *
7223    * Since: 0.6
7224    */
7225   actor_signals[CAPTURED_EVENT] =
7226     g_signal_new (I_("captured-event"),
7227                   G_TYPE_FROM_CLASS (object_class),
7228                   G_SIGNAL_RUN_LAST,
7229                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7230                   _clutter_boolean_handled_accumulator, NULL,
7231                   _clutter_marshal_BOOLEAN__BOXED,
7232                   G_TYPE_BOOLEAN, 1,
7233                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7234
7235   /**
7236    * ClutterActor::paint:
7237    * @actor: the #ClutterActor that received the signal
7238    *
7239    * The ::paint signal is emitted each time an actor is being painted.
7240    *
7241    * Subclasses of #ClutterActor should override the class signal handler
7242    * and paint themselves in that function.
7243    *
7244    * It is possible to connect a handler to the ::paint signal in order
7245    * to set up some custom aspect of a paint.
7246    *
7247    * Since: 0.8
7248    */
7249   actor_signals[PAINT] =
7250     g_signal_new (I_("paint"),
7251                   G_TYPE_FROM_CLASS (object_class),
7252                   G_SIGNAL_RUN_LAST |
7253                   G_SIGNAL_NO_HOOKS,
7254                   G_STRUCT_OFFSET (ClutterActorClass, paint),
7255                   NULL, NULL,
7256                   _clutter_marshal_VOID__VOID,
7257                   G_TYPE_NONE, 0);
7258   /**
7259    * ClutterActor::realize:
7260    * @actor: the #ClutterActor that received the signal
7261    *
7262    * The ::realize signal is emitted each time an actor is being
7263    * realized.
7264    *
7265    * Since: 0.8
7266    */
7267   actor_signals[REALIZE] =
7268     g_signal_new (I_("realize"),
7269                   G_TYPE_FROM_CLASS (object_class),
7270                   G_SIGNAL_RUN_LAST,
7271                   G_STRUCT_OFFSET (ClutterActorClass, realize),
7272                   NULL, NULL,
7273                   _clutter_marshal_VOID__VOID,
7274                   G_TYPE_NONE, 0);
7275   /**
7276    * ClutterActor::unrealize:
7277    * @actor: the #ClutterActor that received the signal
7278    *
7279    * The ::unrealize signal is emitted each time an actor is being
7280    * unrealized.
7281    *
7282    * Since: 0.8
7283    */
7284   actor_signals[UNREALIZE] =
7285     g_signal_new (I_("unrealize"),
7286                   G_TYPE_FROM_CLASS (object_class),
7287                   G_SIGNAL_RUN_LAST,
7288                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7289                   NULL, NULL,
7290                   _clutter_marshal_VOID__VOID,
7291                   G_TYPE_NONE, 0);
7292
7293   /**
7294    * ClutterActor::pick:
7295    * @actor: the #ClutterActor that received the signal
7296    * @color: the #ClutterColor to be used when picking
7297    *
7298    * The ::pick signal is emitted each time an actor is being painted
7299    * in "pick mode". The pick mode is used to identify the actor during
7300    * the event handling phase, or by clutter_stage_get_actor_at_pos().
7301    * The actor should paint its shape using the passed @pick_color.
7302    *
7303    * Subclasses of #ClutterActor should override the class signal handler
7304    * and paint themselves in that function.
7305    *
7306    * It is possible to connect a handler to the ::pick signal in order
7307    * to set up some custom aspect of a paint in pick mode.
7308    *
7309    * Since: 1.0
7310    */
7311   actor_signals[PICK] =
7312     g_signal_new (I_("pick"),
7313                   G_TYPE_FROM_CLASS (object_class),
7314                   G_SIGNAL_RUN_LAST,
7315                   G_STRUCT_OFFSET (ClutterActorClass, pick),
7316                   NULL, NULL,
7317                   _clutter_marshal_VOID__BOXED,
7318                   G_TYPE_NONE, 1,
7319                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7320
7321   /**
7322    * ClutterActor::allocation-changed:
7323    * @actor: the #ClutterActor that emitted the signal
7324    * @box: a #ClutterActorBox with the new allocation
7325    * @flags: #ClutterAllocationFlags for the allocation
7326    *
7327    * The ::allocation-changed signal is emitted when the
7328    * #ClutterActor:allocation property changes. Usually, application
7329    * code should just use the notifications for the :allocation property
7330    * but if you want to track the allocation flags as well, for instance
7331    * to know whether the absolute origin of @actor changed, then you might
7332    * want use this signal instead.
7333    *
7334    * Since: 1.0
7335    */
7336   actor_signals[ALLOCATION_CHANGED] =
7337     g_signal_new (I_("allocation-changed"),
7338                   G_TYPE_FROM_CLASS (object_class),
7339                   G_SIGNAL_RUN_LAST,
7340                   0,
7341                   NULL, NULL,
7342                   _clutter_marshal_VOID__BOXED_FLAGS,
7343                   G_TYPE_NONE, 2,
7344                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7345                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7346
7347   /**
7348    * ClutterActor::transitions-completed:
7349    * @actor: a #ClutterActor
7350    *
7351    * The ::transitions-completed signal is emitted once all transitions
7352    * involving @actor are complete.
7353    *
7354    * Since: 1.10
7355    */
7356   actor_signals[TRANSITIONS_COMPLETED] =
7357     g_signal_new (I_("transitions-completed"),
7358                   G_TYPE_FROM_CLASS (object_class),
7359                   G_SIGNAL_RUN_LAST,
7360                   0,
7361                   NULL, NULL,
7362                   _clutter_marshal_VOID__VOID,
7363                   G_TYPE_NONE, 0);
7364 }
7365
7366 static void
7367 clutter_actor_init (ClutterActor *self)
7368 {
7369   ClutterActorPrivate *priv;
7370
7371   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7372
7373   priv->id = _clutter_context_acquire_id (self);
7374   priv->pick_id = -1;
7375
7376   priv->opacity = 0xff;
7377   priv->show_on_set_parent = TRUE;
7378
7379   priv->needs_width_request = TRUE;
7380   priv->needs_height_request = TRUE;
7381   priv->needs_allocation = TRUE;
7382
7383   priv->cached_width_age = 1;
7384   priv->cached_height_age = 1;
7385
7386   priv->opacity_override = -1;
7387   priv->enable_model_view_transform = TRUE;
7388
7389   /* Initialize an empty paint volume to start with */
7390   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7391   priv->last_paint_volume_valid = TRUE;
7392
7393   priv->transform_valid = FALSE;
7394
7395   /* the default is to stretch the content, to match the
7396    * current behaviour of basically all actors. also, it's
7397    * the easiest thing to compute.
7398    */
7399   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7400   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7401   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7402
7403   /* this flag will be set to TRUE if the actor gets a child
7404    * or if the [xy]-expand flags are explicitly set; until
7405    * then, the actor does not need to expand.
7406    *
7407    * this also allows us to avoid computing the expand flag
7408    * when building up a scene.
7409    */
7410   priv->needs_compute_expand = FALSE;
7411 }
7412
7413 /**
7414  * clutter_actor_new:
7415  *
7416  * Creates a new #ClutterActor.
7417  *
7418  * A newly created actor has a floating reference, which will be sunk
7419  * when it is added to another actor.
7420  *
7421  * Return value: (transfer full): the newly created #ClutterActor
7422  *
7423  * Since: 1.10
7424  */
7425 ClutterActor *
7426 clutter_actor_new (void)
7427 {
7428   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7429 }
7430
7431 /**
7432  * clutter_actor_destroy:
7433  * @self: a #ClutterActor
7434  *
7435  * Destroys an actor.  When an actor is destroyed, it will break any
7436  * references it holds to other objects.  If the actor is inside a
7437  * container, the actor will be removed.
7438  *
7439  * When you destroy a container, its children will be destroyed as well.
7440  *
7441  * Note: you cannot destroy the #ClutterStage returned by
7442  * clutter_stage_get_default().
7443  */
7444 void
7445 clutter_actor_destroy (ClutterActor *self)
7446 {
7447   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7448
7449   g_object_ref (self);
7450
7451   /* avoid recursion while destroying */
7452   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7453     {
7454       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7455
7456       g_object_run_dispose (G_OBJECT (self));
7457
7458       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7459     }
7460
7461   g_object_unref (self);
7462 }
7463
7464 void
7465 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7466                                     ClutterPaintVolume *clip)
7467 {
7468   ClutterActorPrivate *priv = self->priv;
7469   ClutterPaintVolume *pv;
7470   gboolean clipped;
7471
7472   /* Remove queue entry early in the process, otherwise a new
7473      queue_redraw() during signal handling could put back this
7474      object in the stage redraw list (but the entry is freed as
7475      soon as we return from this function, causing a segfault
7476      later)
7477   */
7478   priv->queue_redraw_entry = NULL;
7479
7480   /* If we've been explicitly passed a clip volume then there's
7481    * nothing more to calculate, but otherwise the only thing we know
7482    * is that the change is constrained to the given actor.
7483    *
7484    * The idea is that if we know the paint volume for where the actor
7485    * was last drawn (in eye coordinates) and we also have the paint
7486    * volume for where it will be drawn next (in actor coordinates)
7487    * then if we queue a redraw for both these volumes that will cover
7488    * everything that needs to be redrawn to clear the old view and
7489    * show the latest view of the actor.
7490    *
7491    * Don't clip this redraw if we don't know what position we had for
7492    * the previous redraw since we don't know where to set the clip so
7493    * it will clear the actor as it is currently.
7494    */
7495   if (clip)
7496     {
7497       _clutter_actor_set_queue_redraw_clip (self, clip);
7498       clipped = TRUE;
7499     }
7500   else if (G_LIKELY (priv->last_paint_volume_valid))
7501     {
7502       pv = _clutter_actor_get_paint_volume_mutable (self);
7503       if (pv)
7504         {
7505           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7506
7507           /* make sure we redraw the actors old position... */
7508           _clutter_actor_set_queue_redraw_clip (stage,
7509                                                 &priv->last_paint_volume);
7510           _clutter_actor_signal_queue_redraw (stage, stage);
7511           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7512
7513           /* XXX: Ideally the redraw signal would take a clip volume
7514            * argument, but that would be an ABI break. Until we can
7515            * break the ABI we pass the argument out-of-band
7516            */
7517
7518           /* setup the clip for the actors new position... */
7519           _clutter_actor_set_queue_redraw_clip (self, pv);
7520           clipped = TRUE;
7521         }
7522       else
7523         clipped = FALSE;
7524     }
7525   else
7526     clipped = FALSE;
7527
7528   _clutter_actor_signal_queue_redraw (self, self);
7529
7530   /* Just in case anyone is manually firing redraw signals without
7531    * using the public queue_redraw() API we are careful to ensure that
7532    * our out-of-band clip member is cleared before returning...
7533    *
7534    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7535    */
7536   if (G_LIKELY (clipped))
7537     _clutter_actor_set_queue_redraw_clip (self, NULL);
7538 }
7539
7540 static void
7541 _clutter_actor_get_allocation_clip (ClutterActor *self,
7542                                     ClutterActorBox *clip)
7543 {
7544   ClutterActorBox allocation;
7545
7546   /* XXX: we don't care if we get an out of date allocation here
7547    * because clutter_actor_queue_redraw_with_clip knows to ignore
7548    * the clip if the actor's allocation is invalid.
7549    *
7550    * This is noted because clutter_actor_get_allocation_box does some
7551    * unnecessary work to support buggy code with a comment suggesting
7552    * that it could be changed later which would be good for this use
7553    * case!
7554    */
7555   clutter_actor_get_allocation_box (self, &allocation);
7556
7557   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7558    * actor's own coordinate space but the allocation is in parent
7559    * coordinates */
7560   clip->x1 = 0;
7561   clip->y1 = 0;
7562   clip->x2 = allocation.x2 - allocation.x1;
7563   clip->y2 = allocation.y2 - allocation.y1;
7564 }
7565
7566 void
7567 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7568                                   ClutterRedrawFlags  flags,
7569                                   ClutterPaintVolume *volume,
7570                                   ClutterEffect      *effect)
7571 {
7572   ClutterActorPrivate *priv = self->priv;
7573   ClutterPaintVolume allocation_pv;
7574   ClutterPaintVolume *pv;
7575   gboolean should_free_pv;
7576   ClutterActor *stage;
7577
7578   /* Here's an outline of the actor queue redraw mechanism:
7579    *
7580    * The process starts in one of the following two functions which
7581    * are wrappers for this function:
7582    * clutter_actor_queue_redraw
7583    * _clutter_actor_queue_redraw_with_clip
7584    *
7585    * additionally, an effect can queue a redraw by wrapping this
7586    * function in clutter_effect_queue_rerun
7587    *
7588    * This functions queues an entry in a list associated with the
7589    * stage which is a list of actors that queued a redraw while
7590    * updating the timelines, performing layouting and processing other
7591    * mainloop sources before the next paint starts.
7592    *
7593    * We aim to minimize the processing done at this point because
7594    * there is a good chance other events will happen while updating
7595    * the scenegraph that would invalidate any expensive work we might
7596    * otherwise try to do here. For example we don't try and resolve
7597    * the screen space bounding box of an actor at this stage so as to
7598    * minimize how much of the screen redraw because it's possible
7599    * something else will happen which will force a full redraw anyway.
7600    *
7601    * When all updates are complete and we come to paint the stage then
7602    * we iterate this list and actually emit the "queue-redraw" signals
7603    * for each of the listed actors which will bubble up to the stage
7604    * for each actor and at that point we will transform the actors
7605    * paint volume into screen coordinates to determine the clip region
7606    * for what needs to be redrawn in the next paint.
7607    *
7608    * Besides minimizing redundant work another reason for this
7609    * deferred design is that it's more likely we will be able to
7610    * determine the paint volume of an actor once we've finished
7611    * updating the scenegraph because its allocation should be up to
7612    * date. NB: If we can't determine an actors paint volume then we
7613    * can't automatically queue a clipped redraw which can make a big
7614    * difference to performance.
7615    *
7616    * So the control flow goes like this:
7617    * One of clutter_actor_queue_redraw,
7618    *        _clutter_actor_queue_redraw_with_clip
7619    *     or clutter_effect_queue_rerun
7620    *
7621    * then control moves to:
7622    *   _clutter_stage_queue_actor_redraw
7623    *
7624    * later during _clutter_stage_do_update, once relayouting is done
7625    * and the scenegraph has been updated we will call:
7626    * _clutter_stage_finish_queue_redraws
7627    *
7628    * _clutter_stage_finish_queue_redraws will call
7629    * _clutter_actor_finish_queue_redraw for each listed actor.
7630    * Note: actors *are* allowed to queue further redraws during this
7631    * process (considering clone actors or texture_new_from_actor which
7632    * respond to their source queueing a redraw by queuing a redraw
7633    * themselves). We repeat the process until the list is empty.
7634    *
7635    * This will result in the "queue-redraw" signal being fired for
7636    * each actor which will pass control to the default signal handler:
7637    * clutter_actor_real_queue_redraw
7638    *
7639    * This will bubble up to the stages handler:
7640    * clutter_stage_real_queue_redraw
7641    *
7642    * clutter_stage_real_queue_redraw will transform the actors paint
7643    * volume into screen space and add it as a clip region for the next
7644    * paint.
7645    */
7646
7647   /* ignore queueing a redraw for actors being destroyed */
7648   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7649     return;
7650
7651   stage = _clutter_actor_get_stage_internal (self);
7652
7653   /* Ignore queueing a redraw for actors not descended from a stage */
7654   if (stage == NULL)
7655     return;
7656
7657   /* ignore queueing a redraw on stages that are being destroyed */
7658   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7659     return;
7660
7661   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7662     {
7663       ClutterActorBox allocation_clip;
7664       ClutterVertex origin;
7665
7666       /* If the actor doesn't have a valid allocation then we will
7667        * queue a full stage redraw. */
7668       if (priv->needs_allocation)
7669         {
7670           /* NB: NULL denotes an undefined clip which will result in a
7671            * full redraw... */
7672           _clutter_actor_set_queue_redraw_clip (self, NULL);
7673           _clutter_actor_signal_queue_redraw (self, self);
7674           return;
7675         }
7676
7677       _clutter_paint_volume_init_static (&allocation_pv, self);
7678       pv = &allocation_pv;
7679
7680       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7681
7682       origin.x = allocation_clip.x1;
7683       origin.y = allocation_clip.y1;
7684       origin.z = 0;
7685       clutter_paint_volume_set_origin (pv, &origin);
7686       clutter_paint_volume_set_width (pv,
7687                                       allocation_clip.x2 - allocation_clip.x1);
7688       clutter_paint_volume_set_height (pv,
7689                                        allocation_clip.y2 -
7690                                        allocation_clip.y1);
7691       should_free_pv = TRUE;
7692     }
7693   else
7694     {
7695       pv = volume;
7696       should_free_pv = FALSE;
7697     }
7698
7699   self->priv->queue_redraw_entry =
7700     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7701                                        priv->queue_redraw_entry,
7702                                        self,
7703                                        pv);
7704
7705   if (should_free_pv)
7706     clutter_paint_volume_free (pv);
7707
7708   /* If this is the first redraw queued then we can directly use the
7709      effect parameter */
7710   if (!priv->is_dirty)
7711     priv->effect_to_redraw = effect;
7712   /* Otherwise we need to merge it with the existing effect parameter */
7713   else if (effect != NULL)
7714     {
7715       /* If there's already an effect then we need to use whichever is
7716          later in the chain of actors. Otherwise a full redraw has
7717          already been queued on the actor so we need to ignore the
7718          effect parameter */
7719       if (priv->effect_to_redraw != NULL)
7720         {
7721           if (priv->effects == NULL)
7722             g_warning ("Redraw queued with an effect that is "
7723                        "not applied to the actor");
7724           else
7725             {
7726               const GList *l;
7727
7728               for (l = _clutter_meta_group_peek_metas (priv->effects);
7729                    l != NULL;
7730                    l = l->next)
7731                 {
7732                   if (l->data == priv->effect_to_redraw ||
7733                       l->data == effect)
7734                     priv->effect_to_redraw = l->data;
7735                 }
7736             }
7737         }
7738     }
7739   else
7740     {
7741       /* If no effect is specified then we need to redraw the whole
7742          actor */
7743       priv->effect_to_redraw = NULL;
7744     }
7745
7746   priv->is_dirty = TRUE;
7747 }
7748
7749 /**
7750  * clutter_actor_queue_redraw:
7751  * @self: A #ClutterActor
7752  *
7753  * Queues up a redraw of an actor and any children. The redraw occurs
7754  * once the main loop becomes idle (after the current batch of events
7755  * has been processed, roughly).
7756  *
7757  * Applications rarely need to call this, as redraws are handled
7758  * automatically by modification functions.
7759  *
7760  * This function will not do anything if @self is not visible, or
7761  * if the actor is inside an invisible part of the scenegraph.
7762  *
7763  * Also be aware that painting is a NOP for actors with an opacity of
7764  * 0
7765  *
7766  * When you are implementing a custom actor you must queue a redraw
7767  * whenever some private state changes that will affect painting or
7768  * picking of your actor.
7769  */
7770 void
7771 clutter_actor_queue_redraw (ClutterActor *self)
7772 {
7773   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7774
7775   _clutter_actor_queue_redraw_full (self,
7776                                     0, /* flags */
7777                                     NULL, /* clip volume */
7778                                     NULL /* effect */);
7779 }
7780
7781 /*< private >
7782  * _clutter_actor_queue_redraw_with_clip:
7783  * @self: A #ClutterActor
7784  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7785  *   this queue redraw.
7786  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7787  *   redrawn or %NULL if you are just using a @flag to state your
7788  *   desired clipping.
7789  *
7790  * Queues up a clipped redraw of an actor and any children. The redraw
7791  * occurs once the main loop becomes idle (after the current batch of
7792  * events has been processed, roughly).
7793  *
7794  * If no flags are given the clip volume is defined by @volume
7795  * specified in actor coordinates and tells Clutter that only content
7796  * within this volume has been changed so Clutter can optionally
7797  * optimize the redraw.
7798  *
7799  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7800  * should be %NULL and this tells Clutter to use the actor's current
7801  * allocation as a clip box. This flag can only be used for 2D actors,
7802  * because any actor with depth may be projected outside its
7803  * allocation.
7804  *
7805  * Applications rarely need to call this, as redraws are handled
7806  * automatically by modification functions.
7807  *
7808  * This function will not do anything if @self is not visible, or if
7809  * the actor is inside an invisible part of the scenegraph.
7810  *
7811  * Also be aware that painting is a NOP for actors with an opacity of
7812  * 0
7813  *
7814  * When you are implementing a custom actor you must queue a redraw
7815  * whenever some private state changes that will affect painting or
7816  * picking of your actor.
7817  */
7818 void
7819 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7820                                        ClutterRedrawFlags  flags,
7821                                        ClutterPaintVolume *volume)
7822 {
7823   _clutter_actor_queue_redraw_full (self,
7824                                     flags, /* flags */
7825                                     volume, /* clip volume */
7826                                     NULL /* effect */);
7827 }
7828
7829 static void
7830 _clutter_actor_queue_only_relayout (ClutterActor *self)
7831 {
7832   ClutterActorPrivate *priv = self->priv;
7833
7834   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7835     return;
7836
7837   if (priv->needs_width_request &&
7838       priv->needs_height_request &&
7839       priv->needs_allocation)
7840     return; /* save some cpu cycles */
7841
7842 #if CLUTTER_ENABLE_DEBUG
7843   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7844     {
7845       g_warning ("The actor '%s' is currently inside an allocation "
7846                  "cycle; calling clutter_actor_queue_relayout() is "
7847                  "not recommended",
7848                  _clutter_actor_get_debug_name (self));
7849     }
7850 #endif /* CLUTTER_ENABLE_DEBUG */
7851
7852   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7853 }
7854
7855 /**
7856  * clutter_actor_queue_redraw_with_clip:
7857  * @self: a #ClutterActor
7858  * @clip: (allow-none): a rectangular clip region, or %NULL
7859  *
7860  * Queues a redraw on @self limited to a specific, actor-relative
7861  * rectangular area.
7862  *
7863  * If @clip is %NULL this function is equivalent to
7864  * clutter_actor_queue_redraw().
7865  *
7866  * Since: 1.10
7867  */
7868 void
7869 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7870                                       const cairo_rectangle_int_t *clip)
7871 {
7872   ClutterPaintVolume volume;
7873   ClutterVertex origin;
7874
7875   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7876
7877   if (clip == NULL)
7878     {
7879       clutter_actor_queue_redraw (self);
7880       return;
7881     }
7882
7883   _clutter_paint_volume_init_static (&volume, self);
7884
7885   origin.x = clip->x;
7886   origin.y = clip->y;
7887   origin.z = 0.0f;
7888
7889   clutter_paint_volume_set_origin (&volume, &origin);
7890   clutter_paint_volume_set_width (&volume, clip->width);
7891   clutter_paint_volume_set_height (&volume, clip->height);
7892
7893   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7894
7895   clutter_paint_volume_free (&volume);
7896 }
7897
7898 /**
7899  * clutter_actor_queue_relayout:
7900  * @self: A #ClutterActor
7901  *
7902  * Indicates that the actor's size request or other layout-affecting
7903  * properties may have changed. This function is used inside #ClutterActor
7904  * subclass implementations, not by applications directly.
7905  *
7906  * Queueing a new layout automatically queues a redraw as well.
7907  *
7908  * Since: 0.8
7909  */
7910 void
7911 clutter_actor_queue_relayout (ClutterActor *self)
7912 {
7913   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7914
7915   _clutter_actor_queue_only_relayout (self);
7916   clutter_actor_queue_redraw (self);
7917 }
7918
7919 /**
7920  * clutter_actor_get_preferred_size:
7921  * @self: a #ClutterActor
7922  * @min_width_p: (out) (allow-none): return location for the minimum
7923  *   width, or %NULL
7924  * @min_height_p: (out) (allow-none): return location for the minimum
7925  *   height, or %NULL
7926  * @natural_width_p: (out) (allow-none): return location for the natural
7927  *   width, or %NULL
7928  * @natural_height_p: (out) (allow-none): return location for the natural
7929  *   height, or %NULL
7930  *
7931  * Computes the preferred minimum and natural size of an actor, taking into
7932  * account the actor's geometry management (either height-for-width
7933  * or width-for-height).
7934  *
7935  * The width and height used to compute the preferred height and preferred
7936  * width are the actor's natural ones.
7937  *
7938  * If you need to control the height for the preferred width, or the width for
7939  * the preferred height, you should use clutter_actor_get_preferred_width()
7940  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7941  * geometry management using the #ClutterActor:request-mode property.
7942  *
7943  * Since: 0.8
7944  */
7945 void
7946 clutter_actor_get_preferred_size (ClutterActor *self,
7947                                   gfloat       *min_width_p,
7948                                   gfloat       *min_height_p,
7949                                   gfloat       *natural_width_p,
7950                                   gfloat       *natural_height_p)
7951 {
7952   ClutterActorPrivate *priv;
7953   gfloat min_width, min_height;
7954   gfloat natural_width, natural_height;
7955
7956   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7957
7958   priv = self->priv;
7959
7960   min_width = min_height = 0;
7961   natural_width = natural_height = 0;
7962
7963   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7964     {
7965       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7966       clutter_actor_get_preferred_width (self, -1,
7967                                          &min_width,
7968                                          &natural_width);
7969       clutter_actor_get_preferred_height (self, natural_width,
7970                                           &min_height,
7971                                           &natural_height);
7972     }
7973   else
7974     {
7975       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7976       clutter_actor_get_preferred_height (self, -1,
7977                                           &min_height,
7978                                           &natural_height);
7979       clutter_actor_get_preferred_width (self, natural_height,
7980                                          &min_width,
7981                                          &natural_width);
7982     }
7983
7984   if (min_width_p)
7985     *min_width_p = min_width;
7986
7987   if (min_height_p)
7988     *min_height_p = min_height;
7989
7990   if (natural_width_p)
7991     *natural_width_p = natural_width;
7992
7993   if (natural_height_p)
7994     *natural_height_p = natural_height;
7995 }
7996
7997 /*< private >
7998  * effective_align:
7999  * @align: a #ClutterActorAlign
8000  * @direction: a #ClutterTextDirection
8001  *
8002  * Retrieves the correct alignment depending on the text direction
8003  *
8004  * Return value: the effective alignment
8005  */
8006 static ClutterActorAlign
8007 effective_align (ClutterActorAlign    align,
8008                  ClutterTextDirection direction)
8009 {
8010   ClutterActorAlign res;
8011
8012   switch (align)
8013     {
8014     case CLUTTER_ACTOR_ALIGN_START:
8015       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
8016           ? CLUTTER_ACTOR_ALIGN_END
8017           : CLUTTER_ACTOR_ALIGN_START;
8018       break;
8019
8020     case CLUTTER_ACTOR_ALIGN_END:
8021       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
8022           ? CLUTTER_ACTOR_ALIGN_START
8023           : CLUTTER_ACTOR_ALIGN_END;
8024       break;
8025
8026     default:
8027       res = align;
8028       break;
8029     }
8030
8031   return res;
8032 }
8033
8034 /*< private >
8035  * _clutter_actor_get_effective_x_align:
8036  * @self: a #ClutterActor
8037  *
8038  * Retrieves the effective horizontal alignment, taking into
8039  * consideration the text direction of @self.
8040  *
8041  * Return value: the effective horizontal alignment
8042  */
8043 ClutterActorAlign
8044 _clutter_actor_get_effective_x_align (ClutterActor *self)
8045 {
8046   return effective_align (clutter_actor_get_x_align (self),
8047                           clutter_actor_get_text_direction (self));
8048 }
8049
8050 static inline void
8051 adjust_for_margin (float  margin_start,
8052                    float  margin_end,
8053                    float *minimum_size,
8054                    float *natural_size,
8055                    float *allocated_start,
8056                    float *allocated_end)
8057 {
8058   *minimum_size -= (margin_start + margin_end);
8059   *natural_size -= (margin_start + margin_end);
8060   *allocated_start += margin_start;
8061   *allocated_end -= margin_end;
8062 }
8063
8064 static inline void
8065 adjust_for_alignment (ClutterActorAlign  alignment,
8066                       float              natural_size,
8067                       float             *allocated_start,
8068                       float             *allocated_end)
8069 {
8070   float allocated_size = *allocated_end - *allocated_start;
8071
8072   switch (alignment)
8073     {
8074     case CLUTTER_ACTOR_ALIGN_FILL:
8075       /* do nothing */
8076       break;
8077
8078     case CLUTTER_ACTOR_ALIGN_START:
8079       /* keep start */
8080       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
8081       break;
8082
8083     case CLUTTER_ACTOR_ALIGN_END:
8084       if (allocated_size > natural_size)
8085         {
8086           *allocated_start += (allocated_size - natural_size);
8087           *allocated_end = *allocated_start + natural_size;
8088         }
8089       break;
8090
8091     case CLUTTER_ACTOR_ALIGN_CENTER:
8092       if (allocated_size > natural_size)
8093         {
8094           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
8095           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
8096         }
8097       break;
8098     }
8099 }
8100
8101 /*< private >
8102  * clutter_actor_adjust_width:
8103  * @self: a #ClutterActor
8104  * @minimum_width: (inout): the actor's preferred minimum width, which
8105  *   will be adjusted depending on the margin
8106  * @natural_width: (inout): the actor's preferred natural width, which
8107  *   will be adjusted depending on the margin
8108  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
8109  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
8110  *
8111  * Adjusts the preferred and allocated position and size of an actor,
8112  * depending on the margin and alignment properties.
8113  */
8114 static void
8115 clutter_actor_adjust_width (ClutterActor *self,
8116                             gfloat       *minimum_width,
8117                             gfloat       *natural_width,
8118                             gfloat       *adjusted_x1,
8119                             gfloat       *adjusted_x2)
8120 {
8121   ClutterTextDirection text_dir;
8122   const ClutterLayoutInfo *info;
8123
8124   info = _clutter_actor_get_layout_info_or_defaults (self);
8125   text_dir = clutter_actor_get_text_direction (self);
8126
8127   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
8128
8129   /* this will tweak natural_width to remove the margin, so that
8130    * adjust_for_alignment() will use the correct size
8131    */
8132   adjust_for_margin (info->margin.left, info->margin.right,
8133                      minimum_width, natural_width,
8134                      adjusted_x1, adjusted_x2);
8135
8136   adjust_for_alignment (effective_align (info->x_align, text_dir),
8137                         *natural_width,
8138                         adjusted_x1, adjusted_x2);
8139 }
8140
8141 /*< private >
8142  * clutter_actor_adjust_height:
8143  * @self: a #ClutterActor
8144  * @minimum_height: (inout): the actor's preferred minimum height, which
8145  *   will be adjusted depending on the margin
8146  * @natural_height: (inout): the actor's preferred natural height, which
8147  *   will be adjusted depending on the margin
8148  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
8149  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
8150  *
8151  * Adjusts the preferred and allocated position and size of an actor,
8152  * depending on the margin and alignment properties.
8153  */
8154 static void
8155 clutter_actor_adjust_height (ClutterActor *self,
8156                              gfloat       *minimum_height,
8157                              gfloat       *natural_height,
8158                              gfloat       *adjusted_y1,
8159                              gfloat       *adjusted_y2)
8160 {
8161   const ClutterLayoutInfo *info;
8162
8163   info = _clutter_actor_get_layout_info_or_defaults (self);
8164
8165   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
8166
8167   /* this will tweak natural_height to remove the margin, so that
8168    * adjust_for_alignment() will use the correct size
8169    */
8170   adjust_for_margin (info->margin.top, info->margin.bottom,
8171                      minimum_height, natural_height,
8172                      adjusted_y1,
8173                      adjusted_y2);
8174
8175   /* we don't use effective_align() here, because text direction
8176    * only affects the horizontal axis
8177    */
8178   adjust_for_alignment (info->y_align,
8179                         *natural_height,
8180                         adjusted_y1,
8181                         adjusted_y2);
8182
8183 }
8184
8185 /* looks for a cached size request for this for_size. If not
8186  * found, returns the oldest entry so it can be overwritten */
8187 static gboolean
8188 _clutter_actor_get_cached_size_request (gfloat         for_size,
8189                                         SizeRequest   *cached_size_requests,
8190                                         SizeRequest  **result)
8191 {
8192   guint i;
8193
8194   *result = &cached_size_requests[0];
8195
8196   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
8197     {
8198       SizeRequest *sr;
8199
8200       sr = &cached_size_requests[i];
8201
8202       if (sr->age > 0 &&
8203           sr->for_size == for_size)
8204         {
8205           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8206           *result = sr;
8207           return TRUE;
8208         }
8209       else if (sr->age < (*result)->age)
8210         {
8211           *result = sr;
8212         }
8213     }
8214
8215   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8216
8217   return FALSE;
8218 }
8219
8220 /**
8221  * clutter_actor_get_preferred_width:
8222  * @self: A #ClutterActor
8223  * @for_height: available height when computing the preferred width,
8224  *   or a negative value to indicate that no height is defined
8225  * @min_width_p: (out) (allow-none): return location for minimum width,
8226  *   or %NULL
8227  * @natural_width_p: (out) (allow-none): return location for the natural
8228  *   width, or %NULL
8229  *
8230  * Computes the requested minimum and natural widths for an actor,
8231  * optionally depending on the specified height, or if they are
8232  * already computed, returns the cached values.
8233  *
8234  * An actor may not get its request - depending on the layout
8235  * manager that's in effect.
8236  *
8237  * A request should not incorporate the actor's scale or anchor point;
8238  * those transformations do not affect layout, only rendering.
8239  *
8240  * Since: 0.8
8241  */
8242 void
8243 clutter_actor_get_preferred_width (ClutterActor *self,
8244                                    gfloat        for_height,
8245                                    gfloat       *min_width_p,
8246                                    gfloat       *natural_width_p)
8247 {
8248   float request_min_width, request_natural_width;
8249   SizeRequest *cached_size_request;
8250   const ClutterLayoutInfo *info;
8251   ClutterActorPrivate *priv;
8252   gboolean found_in_cache;
8253
8254   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8255
8256   priv = self->priv;
8257
8258   info = _clutter_actor_get_layout_info_or_defaults (self);
8259
8260   /* we shortcircuit the case of a fixed size set using set_width() */
8261   if (priv->min_width_set && priv->natural_width_set)
8262     {
8263       if (min_width_p != NULL)
8264         *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8265
8266       if (natural_width_p != NULL)
8267         *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8268
8269       return;
8270     }
8271
8272   /* the remaining cases are:
8273    *
8274    *   - either min_width or natural_width have been set
8275    *   - neither min_width or natural_width have been set
8276    *
8277    * in both cases, we go through the cache (and through the actor in case
8278    * of cache misses) and determine the authoritative value depending on
8279    * the *_set flags.
8280    */
8281
8282   if (!priv->needs_width_request)
8283     {
8284       found_in_cache =
8285         _clutter_actor_get_cached_size_request (for_height,
8286                                                 priv->width_requests,
8287                                                 &cached_size_request);
8288     }
8289   else
8290     {
8291       /* if the actor needs a width request we use the first slot */
8292       found_in_cache = FALSE;
8293       cached_size_request = &priv->width_requests[0];
8294     }
8295
8296   if (!found_in_cache)
8297     {
8298       gfloat minimum_width, natural_width;
8299       ClutterActorClass *klass;
8300
8301       minimum_width = natural_width = 0;
8302
8303       /* adjust for the margin */
8304       if (for_height >= 0)
8305         {
8306           for_height -= (info->margin.top + info->margin.bottom);
8307           if (for_height < 0)
8308             for_height = 0;
8309         }
8310
8311       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8312
8313       klass = CLUTTER_ACTOR_GET_CLASS (self);
8314       klass->get_preferred_width (self, for_height,
8315                                   &minimum_width,
8316                                   &natural_width);
8317
8318       /* adjust for the margin */
8319       minimum_width += (info->margin.left + info->margin.right);
8320       natural_width += (info->margin.left + info->margin.right);
8321
8322       /* Due to accumulated float errors, it's better not to warn
8323        * on this, but just fix it.
8324        */
8325       if (natural_width < minimum_width)
8326         natural_width = minimum_width;
8327
8328       cached_size_request->min_size = minimum_width;
8329       cached_size_request->natural_size = natural_width;
8330       cached_size_request->for_size = for_height;
8331       cached_size_request->age = priv->cached_width_age;
8332
8333       priv->cached_width_age += 1;
8334       priv->needs_width_request = FALSE;
8335     }
8336
8337   if (!priv->min_width_set)
8338     request_min_width = cached_size_request->min_size;
8339   else
8340     request_min_width = info->margin.left
8341                       + info->minimum.width
8342                       + info->margin.right;
8343
8344   if (!priv->natural_width_set)
8345     request_natural_width = cached_size_request->natural_size;
8346   else
8347     request_natural_width = info->margin.left
8348                           + info->natural.width
8349                           + info->margin.right;
8350
8351   if (min_width_p)
8352     *min_width_p = request_min_width;
8353
8354   if (natural_width_p)
8355     *natural_width_p = request_natural_width;
8356 }
8357
8358 /**
8359  * clutter_actor_get_preferred_height:
8360  * @self: A #ClutterActor
8361  * @for_width: available width to assume in computing desired height,
8362  *   or a negative value to indicate that no width is defined
8363  * @min_height_p: (out) (allow-none): return location for minimum height,
8364  *   or %NULL
8365  * @natural_height_p: (out) (allow-none): return location for natural
8366  *   height, or %NULL
8367  *
8368  * Computes the requested minimum and natural heights for an actor,
8369  * or if they are already computed, returns the cached values.
8370  *
8371  * An actor may not get its request - depending on the layout
8372  * manager that's in effect.
8373  *
8374  * A request should not incorporate the actor's scale or anchor point;
8375  * those transformations do not affect layout, only rendering.
8376  *
8377  * Since: 0.8
8378  */
8379 void
8380 clutter_actor_get_preferred_height (ClutterActor *self,
8381                                     gfloat        for_width,
8382                                     gfloat       *min_height_p,
8383                                     gfloat       *natural_height_p)
8384 {
8385   float request_min_height, request_natural_height;
8386   SizeRequest *cached_size_request;
8387   const ClutterLayoutInfo *info;
8388   ClutterActorPrivate *priv;
8389   gboolean found_in_cache;
8390
8391   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8392
8393   priv = self->priv;
8394
8395   info = _clutter_actor_get_layout_info_or_defaults (self);
8396
8397   /* we shortcircuit the case of a fixed size set using set_height() */
8398   if (priv->min_height_set && priv->natural_height_set)
8399     {
8400       if (min_height_p != NULL)
8401         *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8402
8403       if (natural_height_p != NULL)
8404         *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8405
8406       return;
8407     }
8408
8409   /* the remaining cases are:
8410    *
8411    *   - either min_height or natural_height have been set
8412    *   - neither min_height or natural_height have been set
8413    *
8414    * in both cases, we go through the cache (and through the actor in case
8415    * of cache misses) and determine the authoritative value depending on
8416    * the *_set flags.
8417    */
8418
8419   if (!priv->needs_height_request)
8420     {
8421       found_in_cache =
8422         _clutter_actor_get_cached_size_request (for_width,
8423                                                 priv->height_requests,
8424                                                 &cached_size_request);
8425     }
8426   else
8427     {
8428       found_in_cache = FALSE;
8429       cached_size_request = &priv->height_requests[0];
8430     }
8431
8432   if (!found_in_cache)
8433     {
8434       gfloat minimum_height, natural_height;
8435       ClutterActorClass *klass;
8436
8437       minimum_height = natural_height = 0;
8438
8439       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8440
8441       /* adjust for margin */
8442       if (for_width >= 0)
8443         {
8444           for_width -= (info->margin.left + info->margin.right);
8445           if (for_width < 0)
8446             for_width = 0;
8447         }
8448
8449       klass = CLUTTER_ACTOR_GET_CLASS (self);
8450       klass->get_preferred_height (self, for_width,
8451                                    &minimum_height,
8452                                    &natural_height);
8453
8454       /* adjust for margin */
8455       minimum_height += (info->margin.top + info->margin.bottom);
8456       natural_height += (info->margin.top + info->margin.bottom);
8457
8458       /* Due to accumulated float errors, it's better not to warn
8459        * on this, but just fix it.
8460        */
8461       if (natural_height < minimum_height)
8462         natural_height = minimum_height;
8463
8464       cached_size_request->min_size = minimum_height;
8465       cached_size_request->natural_size = natural_height;
8466       cached_size_request->for_size = for_width;
8467       cached_size_request->age = priv->cached_height_age;
8468
8469       priv->cached_height_age += 1;
8470       priv->needs_height_request = FALSE;
8471     }
8472
8473   if (!priv->min_height_set)
8474     request_min_height = cached_size_request->min_size;
8475   else
8476     request_min_height = info->margin.top
8477                        + info->minimum.height
8478                        + info->margin.bottom;
8479
8480   if (!priv->natural_height_set)
8481     request_natural_height = cached_size_request->natural_size;
8482   else
8483     request_natural_height = info->margin.top
8484                            + info->natural.height
8485                            + info->margin.bottom;
8486
8487   if (min_height_p)
8488     *min_height_p = request_min_height;
8489
8490   if (natural_height_p)
8491     *natural_height_p = request_natural_height;
8492 }
8493
8494 /**
8495  * clutter_actor_get_allocation_box:
8496  * @self: A #ClutterActor
8497  * @box: (out): the function fills this in with the actor's allocation
8498  *
8499  * Gets the layout box an actor has been assigned. The allocation can
8500  * only be assumed valid inside a paint() method; anywhere else, it
8501  * may be out-of-date.
8502  *
8503  * An allocation does not incorporate the actor's scale or anchor point;
8504  * those transformations do not affect layout, only rendering.
8505  *
8506  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8507  * of functions inside the implementation of the get_preferred_width()
8508  * or get_preferred_height() virtual functions.</note>
8509  *
8510  * Since: 0.8
8511  */
8512 void
8513 clutter_actor_get_allocation_box (ClutterActor    *self,
8514                                   ClutterActorBox *box)
8515 {
8516   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8517
8518   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8519    * which limits calling get_allocation to inside paint() basically; or
8520    * we can 2) force a layout, which could be expensive if someone calls
8521    * get_allocation somewhere silly; or we can 3) just return the latest
8522    * value, allowing it to be out-of-date, and assume people know what
8523    * they are doing.
8524    *
8525    * The least-surprises approach that keeps existing code working is
8526    * likely to be 2). People can end up doing some inefficient things,
8527    * though, and in general code that requires 2) is probably broken.
8528    */
8529
8530   /* this implements 2) */
8531   if (G_UNLIKELY (self->priv->needs_allocation))
8532     {
8533       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8534
8535       /* do not queue a relayout on an unparented actor */
8536       if (stage)
8537         _clutter_stage_maybe_relayout (stage);
8538     }
8539
8540   /* commenting out the code above and just keeping this assigment
8541    * implements 3)
8542    */
8543   *box = self->priv->allocation;
8544 }
8545
8546 /**
8547  * clutter_actor_get_allocation_geometry:
8548  * @self: A #ClutterActor
8549  * @geom: (out): allocation geometry in pixels
8550  *
8551  * Gets the layout box an actor has been assigned.  The allocation can
8552  * only be assumed valid inside a paint() method; anywhere else, it
8553  * may be out-of-date.
8554  *
8555  * An allocation does not incorporate the actor's scale or anchor point;
8556  * those transformations do not affect layout, only rendering.
8557  *
8558  * The returned rectangle is in pixels.
8559  *
8560  * Since: 0.8
8561  */
8562 void
8563 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8564                                        ClutterGeometry *geom)
8565 {
8566   ClutterActorBox box;
8567
8568   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8569   g_return_if_fail (geom != NULL);
8570
8571   clutter_actor_get_allocation_box (self, &box);
8572
8573   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8574   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8575   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8576   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8577 }
8578
8579 static void
8580 clutter_actor_update_constraints (ClutterActor    *self,
8581                                   ClutterActorBox *allocation)
8582 {
8583   ClutterActorPrivate *priv = self->priv;
8584   const GList *constraints, *l;
8585
8586   if (priv->constraints == NULL)
8587     return;
8588
8589   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8590   for (l = constraints; l != NULL; l = l->next)
8591     {
8592       ClutterConstraint *constraint = l->data;
8593       ClutterActorMeta *meta = l->data;
8594
8595       if (clutter_actor_meta_get_enabled (meta))
8596         {
8597           _clutter_constraint_update_allocation (constraint,
8598                                                  self,
8599                                                  allocation);
8600
8601           CLUTTER_NOTE (LAYOUT,
8602                         "Allocation of '%s' after constraint '%s': "
8603                         "{ %.2f, %.2f, %.2f, %.2f }",
8604                         _clutter_actor_get_debug_name (self),
8605                         _clutter_actor_meta_get_debug_name (meta),
8606                         allocation->x1,
8607                         allocation->y1,
8608                         allocation->x2,
8609                         allocation->y2);
8610         }
8611     }
8612 }
8613
8614 /*< private >
8615  * clutter_actor_adjust_allocation:
8616  * @self: a #ClutterActor
8617  * @allocation: (inout): the allocation to adjust
8618  *
8619  * Adjusts the passed allocation box taking into account the actor's
8620  * layout information, like alignment, expansion, and margin.
8621  */
8622 static void
8623 clutter_actor_adjust_allocation (ClutterActor    *self,
8624                                  ClutterActorBox *allocation)
8625 {
8626   ClutterActorBox adj_allocation;
8627   float alloc_width, alloc_height;
8628   float min_width, min_height;
8629   float nat_width, nat_height;
8630   ClutterRequestMode req_mode;
8631
8632   adj_allocation = *allocation;
8633
8634   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8635
8636   /* we want to hit the cache, so we use the public API */
8637   req_mode = clutter_actor_get_request_mode (self);
8638
8639   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8640     {
8641       clutter_actor_get_preferred_width (self, -1,
8642                                          &min_width,
8643                                          &nat_width);
8644       clutter_actor_get_preferred_height (self, alloc_width,
8645                                           &min_height,
8646                                           &nat_height);
8647     }
8648   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8649     {
8650       clutter_actor_get_preferred_height (self, -1,
8651                                           &min_height,
8652                                           &nat_height);
8653       clutter_actor_get_preferred_width (self, alloc_height,
8654                                          &min_width,
8655                                          &nat_width);
8656     }
8657
8658 #ifdef CLUTTER_ENABLE_DEBUG
8659   /* warn about underallocations */
8660   if (_clutter_diagnostic_enabled () &&
8661       (floorf (min_width - alloc_width) > 0 ||
8662        floorf (min_height - alloc_height) > 0))
8663     {
8664       ClutterActor *parent = clutter_actor_get_parent (self);
8665
8666       /* the only actors that are allowed to be underallocated are the Stage,
8667        * as it doesn't have an implicit size, and Actors that specifically
8668        * told us that they want to opt-out from layout control mechanisms
8669        * through the NO_LAYOUT escape hatch.
8670        */
8671       if (parent != NULL &&
8672           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8673         {
8674           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8675                      "of %.2f x %.2f from its parent actor '%s', but its "
8676                      "requested minimum size is of %.2f x %.2f",
8677                      _clutter_actor_get_debug_name (self),
8678                      alloc_width, alloc_height,
8679                      _clutter_actor_get_debug_name (parent),
8680                      min_width, min_height);
8681         }
8682     }
8683 #endif
8684
8685   clutter_actor_adjust_width (self,
8686                               &min_width,
8687                               &nat_width,
8688                               &adj_allocation.x1,
8689                               &adj_allocation.x2);
8690
8691   clutter_actor_adjust_height (self,
8692                                &min_height,
8693                                &nat_height,
8694                                &adj_allocation.y1,
8695                                &adj_allocation.y2);
8696
8697   /* we maintain the invariant that an allocation cannot be adjusted
8698    * to be outside the parent-given box
8699    */
8700   if (adj_allocation.x1 < allocation->x1 ||
8701       adj_allocation.y1 < allocation->y1 ||
8702       adj_allocation.x2 > allocation->x2 ||
8703       adj_allocation.y2 > allocation->y2)
8704     {
8705       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8706                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8707                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8708                  _clutter_actor_get_debug_name (self),
8709                  adj_allocation.x1, adj_allocation.y1,
8710                  adj_allocation.x2 - adj_allocation.x1,
8711                  adj_allocation.y2 - adj_allocation.y1,
8712                  allocation->x1, allocation->y1,
8713                  allocation->x2 - allocation->x1,
8714                  allocation->y2 - allocation->y1);
8715       return;
8716     }
8717
8718   *allocation = adj_allocation;
8719 }
8720
8721 static void
8722 clutter_actor_allocate_internal (ClutterActor           *self,
8723                                  const ClutterActorBox  *allocation,
8724                                  ClutterAllocationFlags  flags)
8725 {
8726   ClutterActorClass *klass;
8727
8728   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8729
8730   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8731                 _clutter_actor_get_debug_name (self));
8732
8733   klass = CLUTTER_ACTOR_GET_CLASS (self);
8734   klass->allocate (self, allocation, flags);
8735
8736   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8737
8738   clutter_actor_queue_redraw (self);
8739 }
8740
8741 /**
8742  * clutter_actor_allocate:
8743  * @self: A #ClutterActor
8744  * @box: new allocation of the actor, in parent-relative coordinates
8745  * @flags: flags that control the allocation
8746  *
8747  * Called by the parent of an actor to assign the actor its size.
8748  * Should never be called by applications (except when implementing
8749  * a container or layout manager).
8750  *
8751  * Actors can know from their allocation box whether they have moved
8752  * with respect to their parent actor. The @flags parameter describes
8753  * additional information about the allocation, for instance whether
8754  * the parent has moved with respect to the stage, for example because
8755  * a grandparent's origin has moved.
8756  *
8757  * Since: 0.8
8758  */
8759 void
8760 clutter_actor_allocate (ClutterActor           *self,
8761                         const ClutterActorBox  *box,
8762                         ClutterAllocationFlags  flags)
8763 {
8764   ClutterActorBox old_allocation, real_allocation;
8765   gboolean origin_changed, child_moved, size_changed;
8766   gboolean stage_allocation_changed;
8767   ClutterActorPrivate *priv;
8768
8769   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8770   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8771     {
8772       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8773                  "which isn't a descendent of the stage!\n",
8774                  self, _clutter_actor_get_debug_name (self));
8775       return;
8776     }
8777
8778   priv = self->priv;
8779
8780   old_allocation = priv->allocation;
8781   real_allocation = *box;
8782
8783   /* constraints are allowed to modify the allocation only here; we do
8784    * this prior to all the other checks so that we can bail out if the
8785    * allocation did not change
8786    */
8787   clutter_actor_update_constraints (self, &real_allocation);
8788
8789   /* adjust the allocation depending on the align/margin properties */
8790   clutter_actor_adjust_allocation (self, &real_allocation);
8791
8792   if (real_allocation.x2 < real_allocation.x1 ||
8793       real_allocation.y2 < real_allocation.y1)
8794     {
8795       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8796                  _clutter_actor_get_debug_name (self),
8797                  real_allocation.x2 - real_allocation.x1,
8798                  real_allocation.y2 - real_allocation.y1);
8799     }
8800
8801   /* we allow 0-sized actors, but not negative-sized ones */
8802   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8803   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8804
8805   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8806
8807   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8808                  real_allocation.y1 != old_allocation.y1);
8809
8810   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8811                   real_allocation.y2 != old_allocation.y2);
8812
8813   if (origin_changed || child_moved || size_changed)
8814     stage_allocation_changed = TRUE;
8815   else
8816     stage_allocation_changed = FALSE;
8817
8818   /* If we get an allocation "out of the blue"
8819    * (we did not queue relayout), then we want to
8820    * ignore it. But if we have needs_allocation set,
8821    * we want to guarantee that allocate() virtual
8822    * method is always called, i.e. that queue_relayout()
8823    * always results in an allocate() invocation on
8824    * an actor.
8825    *
8826    * The optimization here is to avoid re-allocating
8827    * actors that did not queue relayout and were
8828    * not moved.
8829    */
8830   if (!priv->needs_allocation && !stage_allocation_changed)
8831     {
8832       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8833       return;
8834     }
8835
8836   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8837    * clutter_actor_allocate(), it indicates whether the parent has its
8838    * absolute origin moved; when passed in to ClutterActor::allocate()
8839    * virtual method though, it indicates whether the child has its
8840    * absolute origin moved.  So we set it when child_moved is TRUE
8841    */
8842   if (child_moved)
8843     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8844
8845   /* store the flags here, so that they can be propagated by the
8846    * transition code
8847    */
8848   self->priv->allocation_flags = flags;
8849
8850   if (_clutter_actor_get_transition (self, obj_props[PROP_ALLOCATION]) == NULL)
8851     {
8852       _clutter_actor_create_transition (self, obj_props[PROP_ALLOCATION],
8853                                         &priv->allocation,
8854                                         &real_allocation);
8855     }
8856   else
8857     _clutter_actor_update_transition (self, obj_props[PROP_ALLOCATION],
8858                                       &real_allocation);
8859 }
8860
8861 /**
8862  * clutter_actor_set_allocation:
8863  * @self: a #ClutterActor
8864  * @box: a #ClutterActorBox
8865  * @flags: allocation flags
8866  *
8867  * Stores the allocation of @self as defined by @box.
8868  *
8869  * This function can only be called from within the implementation of
8870  * the #ClutterActorClass.allocate() virtual function.
8871  *
8872  * The allocation should have been adjusted to take into account constraints,
8873  * alignment, and margin properties. If you are implementing a #ClutterActor
8874  * subclass that provides its own layout management policy for its children
8875  * instead of using a #ClutterLayoutManager delegate, you should not call
8876  * this function on the children of @self; instead, you should call
8877  * clutter_actor_allocate(), which will adjust the allocation box for
8878  * you.
8879  *
8880  * This function should only be used by subclasses of #ClutterActor
8881  * that wish to store their allocation but cannot chain up to the
8882  * parent's implementation; the default implementation of the
8883  * #ClutterActorClass.allocate() virtual function will call this
8884  * function.
8885  *
8886  * It is important to note that, while chaining up was the recommended
8887  * behaviour for #ClutterActor subclasses prior to the introduction of
8888  * this function, it is recommended to call clutter_actor_set_allocation()
8889  * instead.
8890  *
8891  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8892  * to handle the allocation of its children, this function will call
8893  * the clutter_layout_manager_allocate() function only if the
8894  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8895  * expected that the subclass will call clutter_layout_manager_allocate()
8896  * by itself. For instance, the following code:
8897  *
8898  * |[
8899  * static void
8900  * my_actor_allocate (ClutterActor *actor,
8901  *                    const ClutterActorBox *allocation,
8902  *                    ClutterAllocationFlags flags)
8903  * {
8904  *   ClutterActorBox new_alloc;
8905  *   ClutterAllocationFlags new_flags;
8906  *
8907  *   adjust_allocation (allocation, &amp;new_alloc);
8908  *
8909  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8910  *
8911  *   /&ast; this will use the layout manager set on the actor &ast;/
8912  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8913  * }
8914  * ]|
8915  *
8916  * is equivalent to this:
8917  *
8918  * |[
8919  * static void
8920  * my_actor_allocate (ClutterActor *actor,
8921  *                    const ClutterActorBox *allocation,
8922  *                    ClutterAllocationFlags flags)
8923  * {
8924  *   ClutterLayoutManager *layout;
8925  *   ClutterActorBox new_alloc;
8926  *
8927  *   adjust_allocation (allocation, &amp;new_alloc);
8928  *
8929  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8930  *
8931  *   layout = clutter_actor_get_layout_manager (actor);
8932  *   clutter_layout_manager_allocate (layout,
8933  *                                    CLUTTER_CONTAINER (actor),
8934  *                                    &amp;new_alloc,
8935  *                                    flags);
8936  * }
8937  * ]|
8938  *
8939  * Since: 1.10
8940  */
8941 void
8942 clutter_actor_set_allocation (ClutterActor           *self,
8943                               const ClutterActorBox  *box,
8944                               ClutterAllocationFlags  flags)
8945 {
8946   ClutterActorPrivate *priv;
8947   gboolean changed;
8948
8949   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8950   g_return_if_fail (box != NULL);
8951
8952   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8953     {
8954       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8955                   "can only be called from within the implementation of "
8956                   "the ClutterActor::allocate() virtual function.");
8957       return;
8958     }
8959
8960   priv = self->priv;
8961
8962   g_object_freeze_notify (G_OBJECT (self));
8963
8964   changed = clutter_actor_set_allocation_internal (self, box, flags);
8965
8966   /* we allocate our children before we notify changes in our geometry,
8967    * so that people connecting to properties will be able to get valid
8968    * data out of the sub-tree of the scene graph that has this actor at
8969    * the root.
8970    */
8971   clutter_actor_maybe_layout_children (self, box, flags);
8972
8973   if (changed)
8974     {
8975       ClutterActorBox signal_box = priv->allocation;
8976       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8977
8978       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8979                      &signal_box,
8980                      signal_flags);
8981     }
8982
8983   g_object_thaw_notify (G_OBJECT (self));
8984 }
8985
8986 /**
8987  * clutter_actor_set_geometry:
8988  * @self: A #ClutterActor
8989  * @geometry: A #ClutterGeometry
8990  *
8991  * Sets the actor's fixed position and forces its minimum and natural
8992  * size, in pixels. This means the untransformed actor will have the
8993  * given geometry. This is the same as calling clutter_actor_set_position()
8994  * and clutter_actor_set_size().
8995  *
8996  * Deprecated: 1.10: Use clutter_actor_set_position() and
8997  *   clutter_actor_set_size() instead.
8998  */
8999 void
9000 clutter_actor_set_geometry (ClutterActor          *self,
9001                             const ClutterGeometry *geometry)
9002 {
9003   g_object_freeze_notify (G_OBJECT (self));
9004
9005   clutter_actor_set_position (self, geometry->x, geometry->y);
9006   clutter_actor_set_size (self, geometry->width, geometry->height);
9007
9008   g_object_thaw_notify (G_OBJECT (self));
9009 }
9010
9011 /**
9012  * clutter_actor_get_geometry:
9013  * @self: A #ClutterActor
9014  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
9015  *
9016  * Gets the size and position of an actor relative to its parent
9017  * actor. This is the same as calling clutter_actor_get_position() and
9018  * clutter_actor_get_size(). It tries to "do what you mean" and get the
9019  * requested size and position if the actor's allocation is invalid.
9020  *
9021  * Deprecated: 1.10: Use clutter_actor_get_position() and
9022  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
9023  *   instead.
9024  */
9025 void
9026 clutter_actor_get_geometry (ClutterActor    *self,
9027                             ClutterGeometry *geometry)
9028 {
9029   gfloat x, y, width, height;
9030
9031   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9032   g_return_if_fail (geometry != NULL);
9033
9034   clutter_actor_get_position (self, &x, &y);
9035   clutter_actor_get_size (self, &width, &height);
9036
9037   geometry->x = (int) x;
9038   geometry->y = (int) y;
9039   geometry->width = (int) width;
9040   geometry->height = (int) height;
9041 }
9042
9043 /**
9044  * clutter_actor_set_position:
9045  * @self: A #ClutterActor
9046  * @x: New left position of actor in pixels.
9047  * @y: New top position of actor in pixels.
9048  *
9049  * Sets the actor's fixed position in pixels relative to any parent
9050  * actor.
9051  *
9052  * If a layout manager is in use, this position will override the
9053  * layout manager and force a fixed position.
9054  */
9055 void
9056 clutter_actor_set_position (ClutterActor *self,
9057                             gfloat        x,
9058                             gfloat        y)
9059 {
9060   ClutterPoint new_position;
9061
9062   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9063
9064   clutter_point_init (&new_position, x, y);
9065
9066   if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
9067     {
9068       ClutterPoint cur_position;
9069
9070       cur_position.x = clutter_actor_get_x (self);
9071       cur_position.y = clutter_actor_get_y (self);
9072
9073       _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
9074                                         &cur_position,
9075                                         &new_position);
9076     }
9077   else
9078     _clutter_actor_update_transition (self,
9079                                       obj_props[PROP_POSITION],
9080                                       &new_position);
9081
9082   clutter_actor_queue_relayout (self);
9083 }
9084
9085 /**
9086  * clutter_actor_get_fixed_position_set:
9087  * @self: A #ClutterActor
9088  *
9089  * Checks whether an actor has a fixed position set (and will thus be
9090  * unaffected by any layout manager).
9091  *
9092  * Return value: %TRUE if the fixed position is set on the actor
9093  *
9094  * Since: 0.8
9095  */
9096 gboolean
9097 clutter_actor_get_fixed_position_set (ClutterActor *self)
9098 {
9099   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
9100
9101   return self->priv->position_set;
9102 }
9103
9104 /**
9105  * clutter_actor_set_fixed_position_set:
9106  * @self: A #ClutterActor
9107  * @is_set: whether to use fixed position
9108  *
9109  * Sets whether an actor has a fixed position set (and will thus be
9110  * unaffected by any layout manager).
9111  *
9112  * Since: 0.8
9113  */
9114 void
9115 clutter_actor_set_fixed_position_set (ClutterActor *self,
9116                                       gboolean      is_set)
9117 {
9118   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9119
9120   if (self->priv->position_set == (is_set != FALSE))
9121     return;
9122
9123   self->priv->position_set = is_set != FALSE;
9124   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
9125
9126   clutter_actor_queue_relayout (self);
9127 }
9128
9129 /**
9130  * clutter_actor_move_by:
9131  * @self: A #ClutterActor
9132  * @dx: Distance to move Actor on X axis.
9133  * @dy: Distance to move Actor on Y axis.
9134  *
9135  * Moves an actor by the specified distance relative to its current
9136  * position in pixels.
9137  *
9138  * This function modifies the fixed position of an actor and thus removes
9139  * it from any layout management. Another way to move an actor is with an
9140  * anchor point, see clutter_actor_set_anchor_point().
9141  *
9142  * Since: 0.2
9143  */
9144 void
9145 clutter_actor_move_by (ClutterActor *self,
9146                        gfloat        dx,
9147                        gfloat        dy)
9148 {
9149   const ClutterLayoutInfo *info;
9150   gfloat x, y;
9151
9152   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9153
9154   info = _clutter_actor_get_layout_info_or_defaults (self);
9155   x = info->fixed_pos.x;
9156   y = info->fixed_pos.y;
9157
9158   clutter_actor_set_position (self, x + dx, y + dy);
9159 }
9160
9161 static void
9162 clutter_actor_set_min_width (ClutterActor *self,
9163                              gfloat        min_width)
9164 {
9165   ClutterActorPrivate *priv = self->priv;
9166   ClutterActorBox old = { 0, };
9167   ClutterLayoutInfo *info;
9168
9169   /* if we are setting the size on a top-level actor and the
9170    * backend only supports static top-levels (e.g. framebuffers)
9171    * then we ignore the passed value and we override it with
9172    * the stage implementation's preferred size.
9173    */
9174   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9175       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9176     return;
9177
9178   info = _clutter_actor_get_layout_info (self);
9179
9180   if (priv->min_width_set && min_width == info->minimum.width)
9181     return;
9182
9183   g_object_freeze_notify (G_OBJECT (self));
9184
9185   clutter_actor_store_old_geometry (self, &old);
9186
9187   info->minimum.width = min_width;
9188   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
9189   clutter_actor_set_min_width_set (self, TRUE);
9190
9191   clutter_actor_notify_if_geometry_changed (self, &old);
9192
9193   g_object_thaw_notify (G_OBJECT (self));
9194
9195   clutter_actor_queue_relayout (self);
9196 }
9197
9198 static void
9199 clutter_actor_set_min_height (ClutterActor *self,
9200                               gfloat        min_height)
9201
9202 {
9203   ClutterActorPrivate *priv = self->priv;
9204   ClutterActorBox old = { 0, };
9205   ClutterLayoutInfo *info;
9206
9207   /* if we are setting the size on a top-level actor and the
9208    * backend only supports static top-levels (e.g. framebuffers)
9209    * then we ignore the passed value and we override it with
9210    * the stage implementation's preferred size.
9211    */
9212   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9213       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9214     return;
9215
9216   info = _clutter_actor_get_layout_info (self);
9217
9218   if (priv->min_height_set && min_height == info->minimum.height)
9219     return;
9220
9221   g_object_freeze_notify (G_OBJECT (self));
9222
9223   clutter_actor_store_old_geometry (self, &old);
9224
9225   info->minimum.height = min_height;
9226   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
9227   clutter_actor_set_min_height_set (self, TRUE);
9228
9229   clutter_actor_notify_if_geometry_changed (self, &old);
9230
9231   g_object_thaw_notify (G_OBJECT (self));
9232
9233   clutter_actor_queue_relayout (self);
9234 }
9235
9236 static void
9237 clutter_actor_set_natural_width (ClutterActor *self,
9238                                  gfloat        natural_width)
9239 {
9240   ClutterActorPrivate *priv = self->priv;
9241   ClutterActorBox old = { 0, };
9242   ClutterLayoutInfo *info;
9243
9244   /* if we are setting the size on a top-level actor and the
9245    * backend only supports static top-levels (e.g. framebuffers)
9246    * then we ignore the passed value and we override it with
9247    * the stage implementation's preferred size.
9248    */
9249   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9250       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9251     return;
9252
9253   info = _clutter_actor_get_layout_info (self);
9254
9255   if (priv->natural_width_set && natural_width == info->natural.width)
9256     return;
9257
9258   g_object_freeze_notify (G_OBJECT (self));
9259
9260   clutter_actor_store_old_geometry (self, &old);
9261
9262   info->natural.width = natural_width;
9263   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9264   clutter_actor_set_natural_width_set (self, TRUE);
9265
9266   clutter_actor_notify_if_geometry_changed (self, &old);
9267
9268   g_object_thaw_notify (G_OBJECT (self));
9269
9270   clutter_actor_queue_relayout (self);
9271 }
9272
9273 static void
9274 clutter_actor_set_natural_height (ClutterActor *self,
9275                                   gfloat        natural_height)
9276 {
9277   ClutterActorPrivate *priv = self->priv;
9278   ClutterActorBox old = { 0, };
9279   ClutterLayoutInfo *info;
9280
9281   /* if we are setting the size on a top-level actor and the
9282    * backend only supports static top-levels (e.g. framebuffers)
9283    * then we ignore the passed value and we override it with
9284    * the stage implementation's preferred size.
9285    */
9286   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9287       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9288     return;
9289
9290   info = _clutter_actor_get_layout_info (self);
9291
9292   if (priv->natural_height_set && natural_height == info->natural.height)
9293     return;
9294
9295   g_object_freeze_notify (G_OBJECT (self));
9296
9297   clutter_actor_store_old_geometry (self, &old);
9298
9299   info->natural.height = natural_height;
9300   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9301   clutter_actor_set_natural_height_set (self, TRUE);
9302
9303   clutter_actor_notify_if_geometry_changed (self, &old);
9304
9305   g_object_thaw_notify (G_OBJECT (self));
9306
9307   clutter_actor_queue_relayout (self);
9308 }
9309
9310 static void
9311 clutter_actor_set_min_width_set (ClutterActor *self,
9312                                  gboolean      use_min_width)
9313 {
9314   ClutterActorPrivate *priv = self->priv;
9315   ClutterActorBox old = { 0, };
9316
9317   if (priv->min_width_set == (use_min_width != FALSE))
9318     return;
9319
9320   clutter_actor_store_old_geometry (self, &old);
9321
9322   priv->min_width_set = use_min_width != FALSE;
9323   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9324
9325   clutter_actor_notify_if_geometry_changed (self, &old);
9326
9327   clutter_actor_queue_relayout (self);
9328 }
9329
9330 static void
9331 clutter_actor_set_min_height_set (ClutterActor *self,
9332                                   gboolean      use_min_height)
9333 {
9334   ClutterActorPrivate *priv = self->priv;
9335   ClutterActorBox old = { 0, };
9336
9337   if (priv->min_height_set == (use_min_height != FALSE))
9338     return;
9339
9340   clutter_actor_store_old_geometry (self, &old);
9341
9342   priv->min_height_set = use_min_height != FALSE;
9343   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9344
9345   clutter_actor_notify_if_geometry_changed (self, &old);
9346
9347   clutter_actor_queue_relayout (self);
9348 }
9349
9350 static void
9351 clutter_actor_set_natural_width_set (ClutterActor *self,
9352                                      gboolean      use_natural_width)
9353 {
9354   ClutterActorPrivate *priv = self->priv;
9355   ClutterActorBox old = { 0, };
9356
9357   if (priv->natural_width_set == (use_natural_width != FALSE))
9358     return;
9359
9360   clutter_actor_store_old_geometry (self, &old);
9361
9362   priv->natural_width_set = use_natural_width != FALSE;
9363   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9364
9365   clutter_actor_notify_if_geometry_changed (self, &old);
9366
9367   clutter_actor_queue_relayout (self);
9368 }
9369
9370 static void
9371 clutter_actor_set_natural_height_set (ClutterActor *self,
9372                                       gboolean      use_natural_height)
9373 {
9374   ClutterActorPrivate *priv = self->priv;
9375   ClutterActorBox old = { 0, };
9376
9377   if (priv->natural_height_set == (use_natural_height != FALSE))
9378     return;
9379
9380   clutter_actor_store_old_geometry (self, &old);
9381
9382   priv->natural_height_set = use_natural_height != FALSE;
9383   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9384
9385   clutter_actor_notify_if_geometry_changed (self, &old);
9386
9387   clutter_actor_queue_relayout (self);
9388 }
9389
9390 /**
9391  * clutter_actor_set_request_mode:
9392  * @self: a #ClutterActor
9393  * @mode: the request mode
9394  *
9395  * Sets the geometry request mode of @self.
9396  *
9397  * The @mode determines the order for invoking
9398  * clutter_actor_get_preferred_width() and
9399  * clutter_actor_get_preferred_height()
9400  *
9401  * Since: 1.2
9402  */
9403 void
9404 clutter_actor_set_request_mode (ClutterActor       *self,
9405                                 ClutterRequestMode  mode)
9406 {
9407   ClutterActorPrivate *priv;
9408
9409   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9410
9411   priv = self->priv;
9412
9413   if (priv->request_mode == mode)
9414     return;
9415
9416   priv->request_mode = mode;
9417
9418   priv->needs_width_request = TRUE;
9419   priv->needs_height_request = TRUE;
9420
9421   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9422
9423   clutter_actor_queue_relayout (self);
9424 }
9425
9426 /**
9427  * clutter_actor_get_request_mode:
9428  * @self: a #ClutterActor
9429  *
9430  * Retrieves the geometry request mode of @self
9431  *
9432  * Return value: the request mode for the actor
9433  *
9434  * Since: 1.2
9435  */
9436 ClutterRequestMode
9437 clutter_actor_get_request_mode (ClutterActor *self)
9438 {
9439   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9440                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9441
9442   return self->priv->request_mode;
9443 }
9444
9445 /* variant of set_width() without checks and without notification
9446  * freeze+thaw, for internal usage only
9447  */
9448 static inline void
9449 clutter_actor_set_width_internal (ClutterActor *self,
9450                                   gfloat        width)
9451 {
9452   if (width >= 0)
9453     {
9454       /* the Stage will use the :min-width to control the minimum
9455        * width to be resized to, so we should not be setting it
9456        * along with the :natural-width
9457        */
9458       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9459         clutter_actor_set_min_width (self, width);
9460
9461       clutter_actor_set_natural_width (self, width);
9462     }
9463   else
9464     {
9465       /* we only unset the :natural-width for the Stage */
9466       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9467         clutter_actor_set_min_width_set (self, FALSE);
9468
9469       clutter_actor_set_natural_width_set (self, FALSE);
9470     }
9471 }
9472
9473 /* variant of set_height() without checks and without notification
9474  * freeze+thaw, for internal usage only
9475  */
9476 static inline void
9477 clutter_actor_set_height_internal (ClutterActor *self,
9478                                    gfloat        height)
9479 {
9480   if (height >= 0)
9481     {
9482       /* see the comment above in set_width_internal() */
9483       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9484         clutter_actor_set_min_height (self, height);
9485
9486       clutter_actor_set_natural_height (self, height);
9487     }
9488   else
9489     {
9490       /* see the comment above in set_width_internal() */
9491       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9492         clutter_actor_set_min_height_set (self, FALSE);
9493
9494       clutter_actor_set_natural_height_set (self, FALSE);
9495     }
9496 }
9497
9498 static void
9499 clutter_actor_set_size_internal (ClutterActor      *self,
9500                                  const ClutterSize *size)
9501 {
9502   if (size != NULL)
9503     {
9504       clutter_actor_set_width_internal (self, size->width);
9505       clutter_actor_set_height_internal (self, size->height);
9506     }
9507   else
9508     {
9509       clutter_actor_set_width_internal (self, -1);
9510       clutter_actor_set_height_internal (self, -1);
9511     }
9512 }
9513
9514 /**
9515  * clutter_actor_set_size:
9516  * @self: A #ClutterActor
9517  * @width: New width of actor in pixels, or -1
9518  * @height: New height of actor in pixels, or -1
9519  *
9520  * Sets the actor's size request in pixels. This overrides any
9521  * "normal" size request the actor would have. For example
9522  * a text actor might normally request the size of the text;
9523  * this function would force a specific size instead.
9524  *
9525  * If @width and/or @height are -1 the actor will use its
9526  * "normal" size request instead of overriding it, i.e.
9527  * you can "unset" the size with -1.
9528  *
9529  * This function sets or unsets both the minimum and natural size.
9530  */
9531 void
9532 clutter_actor_set_size (ClutterActor *self,
9533                         gfloat        width,
9534                         gfloat        height)
9535 {
9536   ClutterSize new_size;
9537
9538   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9539
9540   clutter_size_init (&new_size, width, height);
9541
9542   if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9543     {
9544       /* minor optimization: if we don't have a duration then we can
9545        * skip the get_size() below, to avoid the chance of going through
9546        * get_preferred_width() and get_preferred_height() just to jump to
9547        * a new desired size
9548        */
9549       if (clutter_actor_get_easing_duration (self) == 0)
9550         {
9551           g_object_freeze_notify (G_OBJECT (self));
9552
9553           clutter_actor_set_size_internal (self, &new_size);
9554
9555           g_object_thaw_notify (G_OBJECT (self));
9556
9557           return;
9558         }
9559       else
9560         {
9561           ClutterSize cur_size;
9562
9563           clutter_size_init (&cur_size,
9564                              clutter_actor_get_width (self),
9565                              clutter_actor_get_height (self));
9566
9567          _clutter_actor_create_transition (self,
9568                                            obj_props[PROP_SIZE],
9569                                            &cur_size,
9570                                            &new_size);
9571         }
9572     }
9573   else
9574     _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9575
9576   clutter_actor_queue_relayout (self);
9577 }
9578
9579 /**
9580  * clutter_actor_get_size:
9581  * @self: A #ClutterActor
9582  * @width: (out) (allow-none): return location for the width, or %NULL.
9583  * @height: (out) (allow-none): return location for the height, or %NULL.
9584  *
9585  * This function tries to "do what you mean" and return
9586  * the size an actor will have. If the actor has a valid
9587  * allocation, the allocation will be returned; otherwise,
9588  * the actors natural size request will be returned.
9589  *
9590  * If you care whether you get the request vs. the allocation, you
9591  * should probably call a different function like
9592  * clutter_actor_get_allocation_box() or
9593  * clutter_actor_get_preferred_width().
9594  *
9595  * Since: 0.2
9596  */
9597 void
9598 clutter_actor_get_size (ClutterActor *self,
9599                         gfloat       *width,
9600                         gfloat       *height)
9601 {
9602   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9603
9604   if (width)
9605     *width = clutter_actor_get_width (self);
9606
9607   if (height)
9608     *height = clutter_actor_get_height (self);
9609 }
9610
9611 /**
9612  * clutter_actor_get_position:
9613  * @self: a #ClutterActor
9614  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9615  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9616  *
9617  * This function tries to "do what you mean" and tell you where the
9618  * actor is, prior to any transformations. Retrieves the fixed
9619  * position of an actor in pixels, if one has been set; otherwise, if
9620  * the allocation is valid, returns the actor's allocated position;
9621  * otherwise, returns 0,0.
9622  *
9623  * The returned position is in pixels.
9624  *
9625  * Since: 0.6
9626  */
9627 void
9628 clutter_actor_get_position (ClutterActor *self,
9629                             gfloat       *x,
9630                             gfloat       *y)
9631 {
9632   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9633
9634   if (x)
9635     *x = clutter_actor_get_x (self);
9636
9637   if (y)
9638     *y = clutter_actor_get_y (self);
9639 }
9640
9641 /**
9642  * clutter_actor_get_transformed_position:
9643  * @self: A #ClutterActor
9644  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9645  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9646  *
9647  * Gets the absolute position of an actor, in pixels relative to the stage.
9648  *
9649  * Since: 0.8
9650  */
9651 void
9652 clutter_actor_get_transformed_position (ClutterActor *self,
9653                                         gfloat       *x,
9654                                         gfloat       *y)
9655 {
9656   ClutterVertex v1;
9657   ClutterVertex v2;
9658
9659   v1.x = v1.y = v1.z = 0;
9660   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9661
9662   if (x)
9663     *x = v2.x;
9664
9665   if (y)
9666     *y = v2.y;
9667 }
9668
9669 /**
9670  * clutter_actor_get_transformed_size:
9671  * @self: A #ClutterActor
9672  * @width: (out) (allow-none): return location for the width, or %NULL
9673  * @height: (out) (allow-none): return location for the height, or %NULL
9674  *
9675  * Gets the absolute size of an actor in pixels, taking into account the
9676  * scaling factors.
9677  *
9678  * If the actor has a valid allocation, the allocated size will be used.
9679  * If the actor has not a valid allocation then the preferred size will
9680  * be transformed and returned.
9681  *
9682  * If you want the transformed allocation, see
9683  * clutter_actor_get_abs_allocation_vertices() instead.
9684  *
9685  * <note>When the actor (or one of its ancestors) is rotated around the
9686  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9687  * as a generic quadrangle; in that case this function returns the size
9688  * of the smallest rectangle that encapsulates the entire quad. Please
9689  * note that in this case no assumptions can be made about the relative
9690  * position of this envelope to the absolute position of the actor, as
9691  * returned by clutter_actor_get_transformed_position(); if you need this
9692  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9693  * to get the coords of the actual quadrangle.</note>
9694  *
9695  * Since: 0.8
9696  */
9697 void
9698 clutter_actor_get_transformed_size (ClutterActor *self,
9699                                     gfloat       *width,
9700                                     gfloat       *height)
9701 {
9702   ClutterActorPrivate *priv;
9703   ClutterVertex v[4];
9704   gfloat x_min, x_max, y_min, y_max;
9705   gint i;
9706
9707   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9708
9709   priv = self->priv;
9710
9711   /* if the actor hasn't been allocated yet, get the preferred
9712    * size and transform that
9713    */
9714   if (priv->needs_allocation)
9715     {
9716       gfloat natural_width, natural_height;
9717       ClutterActorBox box;
9718
9719       /* Make a fake allocation to transform.
9720        *
9721        * NB: _clutter_actor_transform_and_project_box expects a box in
9722        * the actor's coordinate space... */
9723
9724       box.x1 = 0;
9725       box.y1 = 0;
9726
9727       natural_width = natural_height = 0;
9728       clutter_actor_get_preferred_size (self, NULL, NULL,
9729                                         &natural_width,
9730                                         &natural_height);
9731
9732       box.x2 = natural_width;
9733       box.y2 = natural_height;
9734
9735       _clutter_actor_transform_and_project_box (self, &box, v);
9736     }
9737   else
9738     clutter_actor_get_abs_allocation_vertices (self, v);
9739
9740   x_min = x_max = v[0].x;
9741   y_min = y_max = v[0].y;
9742
9743   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9744     {
9745       if (v[i].x < x_min)
9746         x_min = v[i].x;
9747
9748       if (v[i].x > x_max)
9749         x_max = v[i].x;
9750
9751       if (v[i].y < y_min)
9752         y_min = v[i].y;
9753
9754       if (v[i].y > y_max)
9755         y_max = v[i].y;
9756     }
9757
9758   if (width)
9759     *width  = x_max - x_min;
9760
9761   if (height)
9762     *height = y_max - y_min;
9763 }
9764
9765 /**
9766  * clutter_actor_get_width:
9767  * @self: A #ClutterActor
9768  *
9769  * Retrieves the width of a #ClutterActor.
9770  *
9771  * If the actor has a valid allocation, this function will return the
9772  * width of the allocated area given to the actor.
9773  *
9774  * If the actor does not have a valid allocation, this function will
9775  * return the actor's natural width, that is the preferred width of
9776  * the actor.
9777  *
9778  * If you care whether you get the preferred width or the width that
9779  * has been assigned to the actor, you should probably call a different
9780  * function like clutter_actor_get_allocation_box() to retrieve the
9781  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9782  * preferred width.
9783  *
9784  * If an actor has a fixed width, for instance a width that has been
9785  * assigned using clutter_actor_set_width(), the width returned will
9786  * be the same value.
9787  *
9788  * Return value: the width of the actor, in pixels
9789  */
9790 gfloat
9791 clutter_actor_get_width (ClutterActor *self)
9792 {
9793   ClutterActorPrivate *priv;
9794
9795   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9796
9797   priv = self->priv;
9798
9799   if (priv->needs_allocation)
9800     {
9801       gfloat natural_width = 0;
9802
9803       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9804         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9805       else
9806         {
9807           gfloat natural_height = 0;
9808
9809           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9810           clutter_actor_get_preferred_width (self, natural_height,
9811                                              NULL,
9812                                              &natural_width);
9813         }
9814
9815       return natural_width;
9816     }
9817   else
9818     return priv->allocation.x2 - priv->allocation.x1;
9819 }
9820
9821 /**
9822  * clutter_actor_get_height:
9823  * @self: A #ClutterActor
9824  *
9825  * Retrieves the height of a #ClutterActor.
9826  *
9827  * If the actor has a valid allocation, this function will return the
9828  * height of the allocated area given to the actor.
9829  *
9830  * If the actor does not have a valid allocation, this function will
9831  * return the actor's natural height, that is the preferred height of
9832  * the actor.
9833  *
9834  * If you care whether you get the preferred height or the height that
9835  * has been assigned to the actor, you should probably call a different
9836  * function like clutter_actor_get_allocation_box() to retrieve the
9837  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9838  * preferred height.
9839  *
9840  * If an actor has a fixed height, for instance a height that has been
9841  * assigned using clutter_actor_set_height(), the height returned will
9842  * be the same value.
9843  *
9844  * Return value: the height of the actor, in pixels
9845  */
9846 gfloat
9847 clutter_actor_get_height (ClutterActor *self)
9848 {
9849   ClutterActorPrivate *priv;
9850
9851   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9852
9853   priv = self->priv;
9854
9855   if (priv->needs_allocation)
9856     {
9857       gfloat natural_height = 0;
9858
9859       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9860         {
9861           gfloat natural_width = 0;
9862
9863           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9864           clutter_actor_get_preferred_height (self, natural_width,
9865                                               NULL, &natural_height);
9866         }
9867       else
9868         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9869
9870       return natural_height;
9871     }
9872   else
9873     return priv->allocation.y2 - priv->allocation.y1;
9874 }
9875
9876 /**
9877  * clutter_actor_set_width:
9878  * @self: A #ClutterActor
9879  * @width: Requested new width for the actor, in pixels, or -1
9880  *
9881  * Forces a width on an actor, causing the actor's preferred width
9882  * and height (if any) to be ignored.
9883  *
9884  * If @width is -1 the actor will use its preferred width request
9885  * instead of overriding it, i.e. you can "unset" the width with -1.
9886  *
9887  * This function sets both the minimum and natural size of the actor.
9888  *
9889  * since: 0.2
9890  */
9891 void
9892 clutter_actor_set_width (ClutterActor *self,
9893                          gfloat        width)
9894 {
9895   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9896
9897   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9898     {
9899       float cur_size;
9900
9901       /* minor optimization: if we don't have a duration
9902        * then we can skip the get_width() below, to avoid
9903        * the chance of going through get_preferred_width()
9904        * just to jump to a new desired width.
9905        */
9906       if (clutter_actor_get_easing_duration (self) == 0)
9907         {
9908           g_object_freeze_notify (G_OBJECT (self));
9909
9910           clutter_actor_set_width_internal (self, width);
9911
9912           g_object_thaw_notify (G_OBJECT (self));
9913
9914           return;
9915         }
9916       else
9917         cur_size = clutter_actor_get_width (self);
9918
9919       _clutter_actor_create_transition (self,
9920                                         obj_props[PROP_WIDTH],
9921                                         cur_size,
9922                                         width);
9923     }
9924   else
9925     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9926 }
9927
9928 /**
9929  * clutter_actor_set_height:
9930  * @self: A #ClutterActor
9931  * @height: Requested new height for the actor, in pixels, or -1
9932  *
9933  * Forces a height on an actor, causing the actor's preferred width
9934  * and height (if any) to be ignored.
9935  *
9936  * If @height is -1 the actor will use its preferred height instead of
9937  * overriding it, i.e. you can "unset" the height with -1.
9938  *
9939  * This function sets both the minimum and natural size of the actor.
9940  *
9941  * since: 0.2
9942  */
9943 void
9944 clutter_actor_set_height (ClutterActor *self,
9945                           gfloat        height)
9946 {
9947   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9948
9949   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9950     {
9951       float cur_size;
9952
9953       /* see the comment in clutter_actor_set_width() above */
9954       if (clutter_actor_get_easing_duration (self) == 0)
9955         {
9956           g_object_freeze_notify (G_OBJECT (self));
9957
9958           clutter_actor_set_height_internal (self, height);
9959
9960           g_object_thaw_notify (G_OBJECT (self));
9961
9962           return;
9963         }
9964       else
9965         cur_size = clutter_actor_get_height (self);
9966
9967       _clutter_actor_create_transition (self,
9968                                         obj_props[PROP_HEIGHT],
9969                                         cur_size,
9970                                         height);
9971     }
9972   else
9973     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9974 }
9975
9976 static inline void
9977 clutter_actor_set_x_internal (ClutterActor *self,
9978                               float         x)
9979 {
9980   ClutterActorPrivate *priv = self->priv;
9981   ClutterLayoutInfo *linfo;
9982   ClutterActorBox old = { 0, };
9983
9984   linfo = _clutter_actor_get_layout_info (self);
9985
9986   if (priv->position_set && linfo->fixed_pos.x == x)
9987     return;
9988
9989   clutter_actor_store_old_geometry (self, &old);
9990
9991   linfo->fixed_pos.x = x;
9992   clutter_actor_set_fixed_position_set (self, TRUE);
9993
9994   clutter_actor_notify_if_geometry_changed (self, &old);
9995
9996   clutter_actor_queue_relayout (self);
9997 }
9998
9999 static inline void
10000 clutter_actor_set_y_internal (ClutterActor *self,
10001                               float         y)
10002 {
10003   ClutterActorPrivate *priv = self->priv;
10004   ClutterLayoutInfo *linfo;
10005   ClutterActorBox old = { 0, };
10006
10007   linfo = _clutter_actor_get_layout_info (self);
10008
10009   if (priv->position_set && linfo->fixed_pos.y == y)
10010     return;
10011
10012   clutter_actor_store_old_geometry (self, &old);
10013
10014   linfo->fixed_pos.y = y;
10015   clutter_actor_set_fixed_position_set (self, TRUE);
10016
10017   clutter_actor_notify_if_geometry_changed (self, &old);
10018
10019   clutter_actor_queue_relayout (self);
10020 }
10021
10022 static void
10023 clutter_actor_set_position_internal (ClutterActor       *self,
10024                                      const ClutterPoint *position)
10025 {
10026   ClutterActorPrivate *priv = self->priv;
10027   ClutterLayoutInfo *linfo;
10028   ClutterActorBox old = { 0, };
10029
10030   linfo = _clutter_actor_get_layout_info (self);
10031
10032   if (priv->position_set &&
10033       clutter_point_equals (position, &linfo->fixed_pos))
10034     return;
10035
10036   clutter_actor_store_old_geometry (self, &old);
10037
10038   if (position != NULL)
10039     {
10040       linfo->fixed_pos = *position;
10041       clutter_actor_set_fixed_position_set (self, TRUE);
10042     }
10043   else
10044     clutter_actor_set_fixed_position_set (self, FALSE);
10045
10046   clutter_actor_notify_if_geometry_changed (self, &old);
10047
10048   clutter_actor_queue_relayout (self);
10049 }
10050
10051 /**
10052  * clutter_actor_set_x:
10053  * @self: a #ClutterActor
10054  * @x: the actor's position on the X axis
10055  *
10056  * Sets the actor's X coordinate, relative to its parent, in pixels.
10057  *
10058  * Overrides any layout manager and forces a fixed position for
10059  * the actor.
10060  *
10061  * The #ClutterActor:x property is animatable.
10062  *
10063  * Since: 0.6
10064  */
10065 void
10066 clutter_actor_set_x (ClutterActor *self,
10067                      gfloat        x)
10068 {
10069   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10070
10071   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
10072     {
10073       float cur_position = clutter_actor_get_x (self);
10074
10075       _clutter_actor_create_transition (self, obj_props[PROP_X],
10076                                         cur_position,
10077                                         x);
10078     }
10079   else
10080     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
10081 }
10082
10083 /**
10084  * clutter_actor_set_y:
10085  * @self: a #ClutterActor
10086  * @y: the actor's position on the Y axis
10087  *
10088  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
10089  *
10090  * Overrides any layout manager and forces a fixed position for
10091  * the actor.
10092  *
10093  * The #ClutterActor:y property is animatable.
10094  *
10095  * Since: 0.6
10096  */
10097 void
10098 clutter_actor_set_y (ClutterActor *self,
10099                      gfloat        y)
10100 {
10101   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10102
10103   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
10104     {
10105       float cur_position = clutter_actor_get_y (self);
10106
10107       _clutter_actor_create_transition (self, obj_props[PROP_Y],
10108                                         cur_position,
10109                                         y);
10110     }
10111   else
10112     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
10113 }
10114
10115 /**
10116  * clutter_actor_get_x:
10117  * @self: A #ClutterActor
10118  *
10119  * Retrieves the X coordinate of a #ClutterActor.
10120  *
10121  * This function tries to "do what you mean", by returning the
10122  * correct value depending on the actor's state.
10123  *
10124  * If the actor has a valid allocation, this function will return
10125  * the X coordinate of the origin of the allocation box.
10126  *
10127  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
10128  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10129  * function will return that coordinate.
10130  *
10131  * If both the allocation and a fixed position are missing, this function
10132  * will return 0.
10133  *
10134  * Return value: the X coordinate, in pixels, ignoring any
10135  *   transformation (i.e. scaling, rotation)
10136  */
10137 gfloat
10138 clutter_actor_get_x (ClutterActor *self)
10139 {
10140   ClutterActorPrivate *priv;
10141
10142   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10143
10144   priv = self->priv;
10145
10146   if (priv->needs_allocation)
10147     {
10148       if (priv->position_set)
10149         {
10150           const ClutterLayoutInfo *info;
10151
10152           info = _clutter_actor_get_layout_info_or_defaults (self);
10153
10154           return info->fixed_pos.x;
10155         }
10156       else
10157         return 0;
10158     }
10159   else
10160     return priv->allocation.x1;
10161 }
10162
10163 /**
10164  * clutter_actor_get_y:
10165  * @self: A #ClutterActor
10166  *
10167  * Retrieves the Y coordinate of a #ClutterActor.
10168  *
10169  * This function tries to "do what you mean", by returning the
10170  * correct value depending on the actor's state.
10171  *
10172  * If the actor has a valid allocation, this function will return
10173  * the Y coordinate of the origin of the allocation box.
10174  *
10175  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
10176  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
10177  * function will return that coordinate.
10178  *
10179  * If both the allocation and a fixed position are missing, this function
10180  * will return 0.
10181  *
10182  * Return value: the Y coordinate, in pixels, ignoring any
10183  *   transformation (i.e. scaling, rotation)
10184  */
10185 gfloat
10186 clutter_actor_get_y (ClutterActor *self)
10187 {
10188   ClutterActorPrivate *priv;
10189
10190   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10191
10192   priv = self->priv;
10193
10194   if (priv->needs_allocation)
10195     {
10196       if (priv->position_set)
10197         {
10198           const ClutterLayoutInfo *info;
10199
10200           info = _clutter_actor_get_layout_info_or_defaults (self);
10201
10202           return info->fixed_pos.y;
10203         }
10204       else
10205         return 0;
10206     }
10207   else
10208     return priv->allocation.y1;
10209 }
10210
10211 /**
10212  * clutter_actor_set_scale:
10213  * @self: A #ClutterActor
10214  * @scale_x: double factor to scale actor by horizontally.
10215  * @scale_y: double factor to scale actor by vertically.
10216  *
10217  * Scales an actor with the given factors. The scaling is relative to
10218  * the scale center and the anchor point. The scale center is
10219  * unchanged by this function and defaults to 0,0.
10220  *
10221  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10222  * animatable.
10223  *
10224  * Since: 0.2
10225  */
10226 void
10227 clutter_actor_set_scale (ClutterActor *self,
10228                          gdouble       scale_x,
10229                          gdouble       scale_y)
10230 {
10231   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10232
10233   g_object_freeze_notify (G_OBJECT (self));
10234
10235   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10236   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10237
10238   g_object_thaw_notify (G_OBJECT (self));
10239 }
10240
10241 /**
10242  * clutter_actor_set_scale_full:
10243  * @self: A #ClutterActor
10244  * @scale_x: double factor to scale actor by horizontally.
10245  * @scale_y: double factor to scale actor by vertically.
10246  * @center_x: X coordinate of the center of the scale.
10247  * @center_y: Y coordinate of the center of the scale
10248  *
10249  * Scales an actor with the given factors around the given center
10250  * point. The center point is specified in pixels relative to the
10251  * anchor point (usually the top left corner of the actor).
10252  *
10253  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10254  * are animatable.
10255  *
10256  * Since: 1.0
10257  */
10258 void
10259 clutter_actor_set_scale_full (ClutterActor *self,
10260                               gdouble       scale_x,
10261                               gdouble       scale_y,
10262                               gfloat        center_x,
10263                               gfloat        center_y)
10264 {
10265   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10266
10267   g_object_freeze_notify (G_OBJECT (self));
10268
10269   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10270   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10271   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10272   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10273
10274   g_object_thaw_notify (G_OBJECT (self));
10275 }
10276
10277 /**
10278  * clutter_actor_set_scale_with_gravity:
10279  * @self: A #ClutterActor
10280  * @scale_x: double factor to scale actor by horizontally.
10281  * @scale_y: double factor to scale actor by vertically.
10282  * @gravity: the location of the scale center expressed as a compass
10283  * direction.
10284  *
10285  * Scales an actor with the given factors around the given
10286  * center point. The center point is specified as one of the compass
10287  * directions in #ClutterGravity. For example, setting it to north
10288  * will cause the top of the actor to remain unchanged and the rest of
10289  * the actor to expand left, right and downwards.
10290  *
10291  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10292  * animatable.
10293  *
10294  * Since: 1.0
10295  */
10296 void
10297 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
10298                                       gdouble         scale_x,
10299                                       gdouble         scale_y,
10300                                       ClutterGravity  gravity)
10301 {
10302   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10303
10304   g_object_freeze_notify (G_OBJECT (self));
10305
10306   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10307   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10308   clutter_actor_set_scale_gravity (self, gravity);
10309
10310   g_object_thaw_notify (G_OBJECT (self));
10311 }
10312
10313 /**
10314  * clutter_actor_get_scale:
10315  * @self: A #ClutterActor
10316  * @scale_x: (out) (allow-none): Location to store horizonal
10317  *   scale factor, or %NULL.
10318  * @scale_y: (out) (allow-none): Location to store vertical
10319  *   scale factor, or %NULL.
10320  *
10321  * Retrieves an actors scale factors.
10322  *
10323  * Since: 0.2
10324  */
10325 void
10326 clutter_actor_get_scale (ClutterActor *self,
10327                          gdouble      *scale_x,
10328                          gdouble      *scale_y)
10329 {
10330   const ClutterTransformInfo *info;
10331
10332   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10333
10334   info = _clutter_actor_get_transform_info_or_defaults (self);
10335
10336   if (scale_x)
10337     *scale_x = info->scale_x;
10338
10339   if (scale_y)
10340     *scale_y = info->scale_y;
10341 }
10342
10343 /**
10344  * clutter_actor_get_scale_center:
10345  * @self: A #ClutterActor
10346  * @center_x: (out) (allow-none): Location to store the X position
10347  *   of the scale center, or %NULL.
10348  * @center_y: (out) (allow-none): Location to store the Y position
10349  *   of the scale center, or %NULL.
10350  *
10351  * Retrieves the scale center coordinate in pixels relative to the top
10352  * left corner of the actor. If the scale center was specified using a
10353  * #ClutterGravity this will calculate the pixel offset using the
10354  * current size of the actor.
10355  *
10356  * Since: 1.0
10357  */
10358 void
10359 clutter_actor_get_scale_center (ClutterActor *self,
10360                                 gfloat       *center_x,
10361                                 gfloat       *center_y)
10362 {
10363   const ClutterTransformInfo *info;
10364
10365   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10366
10367   info = _clutter_actor_get_transform_info_or_defaults (self);
10368
10369   clutter_anchor_coord_get_units (self, &info->scale_center,
10370                                   center_x,
10371                                   center_y,
10372                                   NULL);
10373 }
10374
10375 /**
10376  * clutter_actor_get_scale_gravity:
10377  * @self: A #ClutterActor
10378  *
10379  * Retrieves the scale center as a compass direction. If the scale
10380  * center was specified in pixels or units this will return
10381  * %CLUTTER_GRAVITY_NONE.
10382  *
10383  * Return value: the scale gravity
10384  *
10385  * Since: 1.0
10386  */
10387 ClutterGravity
10388 clutter_actor_get_scale_gravity (ClutterActor *self)
10389 {
10390   const ClutterTransformInfo *info;
10391
10392   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10393
10394   info = _clutter_actor_get_transform_info_or_defaults (self);
10395
10396   return clutter_anchor_coord_get_gravity (&info->scale_center);
10397 }
10398
10399 static inline void
10400 clutter_actor_set_opacity_internal (ClutterActor *self,
10401                                     guint8        opacity)
10402 {
10403   ClutterActorPrivate *priv = self->priv;
10404
10405   if (priv->opacity != opacity)
10406     {
10407       priv->opacity = opacity;
10408
10409       /* Queue a redraw from the flatten effect so that it can use
10410          its cached image if available instead of having to redraw the
10411          actual actor. If it doesn't end up using the FBO then the
10412          effect is still able to continue the paint anyway. If there
10413          is no flatten effect yet then this is equivalent to queueing
10414          a full redraw */
10415       _clutter_actor_queue_redraw_full (self,
10416                                         0, /* flags */
10417                                         NULL, /* clip */
10418                                         priv->flatten_effect);
10419
10420       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10421     }
10422 }
10423
10424 /**
10425  * clutter_actor_set_opacity:
10426  * @self: A #ClutterActor
10427  * @opacity: New opacity value for the actor.
10428  *
10429  * Sets the actor's opacity, with zero being completely transparent and
10430  * 255 (0xff) being fully opaque.
10431  *
10432  * The #ClutterActor:opacity property is animatable.
10433  */
10434 void
10435 clutter_actor_set_opacity (ClutterActor *self,
10436                            guint8        opacity)
10437 {
10438   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10439
10440   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10441     {
10442       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10443                                         self->priv->opacity,
10444                                         opacity);
10445     }
10446   else
10447     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10448 }
10449
10450 /*
10451  * clutter_actor_get_paint_opacity_internal:
10452  * @self: a #ClutterActor
10453  *
10454  * Retrieves the absolute opacity of the actor, as it appears on the stage
10455  *
10456  * This function does not do type checks
10457  *
10458  * Return value: the absolute opacity of the actor
10459  */
10460 static guint8
10461 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10462 {
10463   ClutterActorPrivate *priv = self->priv;
10464   ClutterActor *parent;
10465
10466   /* override the top-level opacity to always be 255; even in
10467    * case of ClutterStage:use-alpha being TRUE we want the rest
10468    * of the scene to be painted
10469    */
10470   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10471     return 255;
10472
10473   if (priv->opacity_override >= 0)
10474     return priv->opacity_override;
10475
10476   parent = priv->parent;
10477
10478   /* Factor in the actual actors opacity with parents */
10479   if (parent != NULL)
10480     {
10481       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10482
10483       if (opacity != 0xff)
10484         return (opacity * priv->opacity) / 0xff;
10485     }
10486
10487   return priv->opacity;
10488
10489 }
10490
10491 /**
10492  * clutter_actor_get_paint_opacity:
10493  * @self: A #ClutterActor
10494  *
10495  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10496  *
10497  * This function traverses the hierarchy chain and composites the opacity of
10498  * the actor with that of its parents.
10499  *
10500  * This function is intended for subclasses to use in the paint virtual
10501  * function, to paint themselves with the correct opacity.
10502  *
10503  * Return value: The actor opacity value.
10504  *
10505  * Since: 0.8
10506  */
10507 guint8
10508 clutter_actor_get_paint_opacity (ClutterActor *self)
10509 {
10510   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10511
10512   return clutter_actor_get_paint_opacity_internal (self);
10513 }
10514
10515 /**
10516  * clutter_actor_get_opacity:
10517  * @self: a #ClutterActor
10518  *
10519  * Retrieves the opacity value of an actor, as set by
10520  * clutter_actor_set_opacity().
10521  *
10522  * For retrieving the absolute opacity of the actor inside a paint
10523  * virtual function, see clutter_actor_get_paint_opacity().
10524  *
10525  * Return value: the opacity of the actor
10526  */
10527 guint8
10528 clutter_actor_get_opacity (ClutterActor *self)
10529 {
10530   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10531
10532   return self->priv->opacity;
10533 }
10534
10535 /**
10536  * clutter_actor_set_offscreen_redirect:
10537  * @self: A #ClutterActor
10538  * @redirect: New offscreen redirect flags for the actor.
10539  *
10540  * Defines the circumstances where the actor should be redirected into
10541  * an offscreen image. The offscreen image is used to flatten the
10542  * actor into a single image while painting for two main reasons.
10543  * Firstly, when the actor is painted a second time without any of its
10544  * contents changing it can simply repaint the cached image without
10545  * descending further down the actor hierarchy. Secondly, it will make
10546  * the opacity look correct even if there are overlapping primitives
10547  * in the actor.
10548  *
10549  * Caching the actor could in some cases be a performance win and in
10550  * some cases be a performance lose so it is important to determine
10551  * which value is right for an actor before modifying this value. For
10552  * example, there is never any reason to flatten an actor that is just
10553  * a single texture (such as a #ClutterTexture) because it is
10554  * effectively already cached in an image so the offscreen would be
10555  * redundant. Also if the actor contains primitives that are far apart
10556  * with a large transparent area in the middle (such as a large
10557  * CluterGroup with a small actor in the top left and a small actor in
10558  * the bottom right) then the cached image will contain the entire
10559  * image of the large area and the paint will waste time blending all
10560  * of the transparent pixels in the middle.
10561  *
10562  * The default method of implementing opacity on a container simply
10563  * forwards on the opacity to all of the children. If the children are
10564  * overlapping then it will appear as if they are two separate glassy
10565  * objects and there will be a break in the color where they
10566  * overlap. By redirecting to an offscreen buffer it will be as if the
10567  * two opaque objects are combined into one and then made transparent
10568  * which is usually what is expected.
10569  *
10570  * The image below demonstrates the difference between redirecting and
10571  * not. The image shows two Clutter groups, each containing a red and
10572  * a green rectangle which overlap. The opacity on the group is set to
10573  * 128 (which is 50%). When the offscreen redirect is not used, the
10574  * red rectangle can be seen through the blue rectangle as if the two
10575  * rectangles were separately transparent. When the redirect is used
10576  * the group as a whole is transparent instead so the red rectangle is
10577  * not visible where they overlap.
10578  *
10579  * <figure id="offscreen-redirect">
10580  *   <title>Sample of using an offscreen redirect for transparency</title>
10581  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10582  * </figure>
10583  *
10584  * The default value for this property is 0, so we effectively will
10585  * never redirect an actor offscreen by default. This means that there
10586  * are times that transparent actors may look glassy as described
10587  * above. The reason this is the default is because there is a
10588  * performance trade off between quality and performance here. In many
10589  * cases the default form of glassy opacity looks good enough, but if
10590  * it's not you will need to set the
10591  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10592  * redirection for opacity.
10593  *
10594  * Custom actors that don't contain any overlapping primitives are
10595  * recommended to override the has_overlaps() virtual to return %FALSE
10596  * for maximum efficiency.
10597  *
10598  * Since: 1.8
10599  */
10600 void
10601 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10602                                       ClutterOffscreenRedirect redirect)
10603 {
10604   ClutterActorPrivate *priv;
10605
10606   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10607
10608   priv = self->priv;
10609
10610   if (priv->offscreen_redirect != redirect)
10611     {
10612       priv->offscreen_redirect = redirect;
10613
10614       /* Queue a redraw from the effect so that it can use its cached
10615          image if available instead of having to redraw the actual
10616          actor. If it doesn't end up using the FBO then the effect is
10617          still able to continue the paint anyway. If there is no
10618          effect then this is equivalent to queuing a full redraw */
10619       _clutter_actor_queue_redraw_full (self,
10620                                         0, /* flags */
10621                                         NULL, /* clip */
10622                                         priv->flatten_effect);
10623
10624       g_object_notify_by_pspec (G_OBJECT (self),
10625                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10626     }
10627 }
10628
10629 /**
10630  * clutter_actor_get_offscreen_redirect:
10631  * @self: a #ClutterActor
10632  *
10633  * Retrieves whether to redirect the actor to an offscreen buffer, as
10634  * set by clutter_actor_set_offscreen_redirect().
10635  *
10636  * Return value: the value of the offscreen-redirect property of the actor
10637  *
10638  * Since: 1.8
10639  */
10640 ClutterOffscreenRedirect
10641 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10642 {
10643   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10644
10645   return self->priv->offscreen_redirect;
10646 }
10647
10648 /**
10649  * clutter_actor_set_name:
10650  * @self: A #ClutterActor
10651  * @name: Textual tag to apply to actor
10652  *
10653  * Sets the given name to @self. The name can be used to identify
10654  * a #ClutterActor.
10655  */
10656 void
10657 clutter_actor_set_name (ClutterActor *self,
10658                         const gchar  *name)
10659 {
10660   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10661
10662   g_free (self->priv->name);
10663   self->priv->name = g_strdup (name);
10664
10665   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10666 }
10667
10668 /**
10669  * clutter_actor_get_name:
10670  * @self: A #ClutterActor
10671  *
10672  * Retrieves the name of @self.
10673  *
10674  * Return value: the name of the actor, or %NULL. The returned string is
10675  *   owned by the actor and should not be modified or freed.
10676  */
10677 const gchar *
10678 clutter_actor_get_name (ClutterActor *self)
10679 {
10680   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10681
10682   return self->priv->name;
10683 }
10684
10685 /**
10686  * clutter_actor_get_gid:
10687  * @self: A #ClutterActor
10688  *
10689  * Retrieves the unique id for @self.
10690  *
10691  * Return value: Globally unique value for this object instance.
10692  *
10693  * Since: 0.6
10694  *
10695  * Deprecated: 1.8: The id is not used any longer.
10696  */
10697 guint32
10698 clutter_actor_get_gid (ClutterActor *self)
10699 {
10700   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10701
10702   return self->priv->id;
10703 }
10704
10705 static inline void
10706 clutter_actor_set_depth_internal (ClutterActor *self,
10707                                   float         depth)
10708 {
10709   ClutterTransformInfo *info;
10710
10711   info = _clutter_actor_get_transform_info (self);
10712
10713   if (info->depth != depth)
10714     {
10715       /* Sets Z value - XXX 2.0: should we invert? */
10716       info->depth = depth;
10717
10718       self->priv->transform_valid = FALSE;
10719
10720       /* FIXME - remove this crap; sadly, there are still containers
10721        * in Clutter that depend on this utter brain damage
10722        */
10723       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10724
10725       clutter_actor_queue_redraw (self);
10726
10727       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10728     }
10729 }
10730
10731 /**
10732  * clutter_actor_set_depth:
10733  * @self: a #ClutterActor
10734  * @depth: Z co-ord
10735  *
10736  * Sets the Z coordinate of @self to @depth.
10737  *
10738  * The unit used by @depth is dependant on the perspective setup. See
10739  * also clutter_stage_set_perspective().
10740  */
10741 void
10742 clutter_actor_set_depth (ClutterActor *self,
10743                          gfloat        depth)
10744 {
10745   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10746
10747   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10748     {
10749       const ClutterTransformInfo *info;
10750
10751       info = _clutter_actor_get_transform_info_or_defaults (self);
10752
10753       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10754                                         info->depth,
10755                                         depth);
10756     }
10757   else
10758     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10759
10760   clutter_actor_queue_redraw (self);
10761 }
10762
10763 /**
10764  * clutter_actor_get_depth:
10765  * @self: a #ClutterActor
10766  *
10767  * Retrieves the depth of @self.
10768  *
10769  * Return value: the depth of the actor
10770  */
10771 gfloat
10772 clutter_actor_get_depth (ClutterActor *self)
10773 {
10774   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10775
10776   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10777 }
10778
10779 /**
10780  * clutter_actor_set_rotation:
10781  * @self: a #ClutterActor
10782  * @axis: the axis of rotation
10783  * @angle: the angle of rotation
10784  * @x: X coordinate of the rotation center
10785  * @y: Y coordinate of the rotation center
10786  * @z: Z coordinate of the rotation center
10787  *
10788  * Sets the rotation angle of @self around the given axis.
10789  *
10790  * The rotation center coordinates used depend on the value of @axis:
10791  * <itemizedlist>
10792  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10793  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10794  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10795  * </itemizedlist>
10796  *
10797  * The rotation coordinates are relative to the anchor point of the
10798  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10799  * point is set, the upper left corner is assumed as the origin.
10800  *
10801  * Since: 0.8
10802  */
10803 void
10804 clutter_actor_set_rotation (ClutterActor      *self,
10805                             ClutterRotateAxis  axis,
10806                             gdouble            angle,
10807                             gfloat             x,
10808                             gfloat             y,
10809                             gfloat             z)
10810 {
10811   ClutterVertex v;
10812
10813   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10814
10815   v.x = x;
10816   v.y = y;
10817   v.z = z;
10818
10819   g_object_freeze_notify (G_OBJECT (self));
10820
10821   clutter_actor_set_rotation_angle (self, axis, angle);
10822   clutter_actor_set_rotation_center_internal (self, axis, &v);
10823
10824   g_object_thaw_notify (G_OBJECT (self));
10825 }
10826
10827 /**
10828  * clutter_actor_set_z_rotation_from_gravity:
10829  * @self: a #ClutterActor
10830  * @angle: the angle of rotation
10831  * @gravity: the center point of the rotation
10832  *
10833  * Sets the rotation angle of @self around the Z axis using the center
10834  * point specified as a compass point. For example to rotate such that
10835  * the center of the actor remains static you can use
10836  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10837  * will move accordingly.
10838  *
10839  * Since: 1.0
10840  */
10841 void
10842 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10843                                            gdouble         angle,
10844                                            ClutterGravity  gravity)
10845 {
10846   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10847
10848   if (gravity == CLUTTER_GRAVITY_NONE)
10849     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10850   else
10851     {
10852       GObject *obj = G_OBJECT (self);
10853       ClutterTransformInfo *info;
10854
10855       info = _clutter_actor_get_transform_info (self);
10856
10857       g_object_freeze_notify (obj);
10858
10859       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10860
10861       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10862       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10863       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10864
10865       g_object_thaw_notify (obj);
10866     }
10867 }
10868
10869 /**
10870  * clutter_actor_get_rotation:
10871  * @self: a #ClutterActor
10872  * @axis: the axis of rotation
10873  * @x: (out): return value for the X coordinate of the center of rotation
10874  * @y: (out): return value for the Y coordinate of the center of rotation
10875  * @z: (out): return value for the Z coordinate of the center of rotation
10876  *
10877  * Retrieves the angle and center of rotation on the given axis,
10878  * set using clutter_actor_set_rotation().
10879  *
10880  * Return value: the angle of rotation
10881  *
10882  * Since: 0.8
10883  */
10884 gdouble
10885 clutter_actor_get_rotation (ClutterActor      *self,
10886                             ClutterRotateAxis  axis,
10887                             gfloat            *x,
10888                             gfloat            *y,
10889                             gfloat            *z)
10890 {
10891   const ClutterTransformInfo *info;
10892   const AnchorCoord *anchor_coord;
10893   gdouble retval = 0;
10894
10895   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10896
10897   info = _clutter_actor_get_transform_info_or_defaults (self);
10898
10899   switch (axis)
10900     {
10901     case CLUTTER_X_AXIS:
10902       anchor_coord = &info->rx_center;
10903       retval = info->rx_angle;
10904       break;
10905
10906     case CLUTTER_Y_AXIS:
10907       anchor_coord = &info->ry_center;
10908       retval = info->ry_angle;
10909       break;
10910
10911     case CLUTTER_Z_AXIS:
10912       anchor_coord = &info->rz_center;
10913       retval = info->rz_angle;
10914       break;
10915
10916     default:
10917       anchor_coord = NULL;
10918       retval = 0.0;
10919       break;
10920     }
10921
10922   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10923
10924   return retval;
10925 }
10926
10927 /**
10928  * clutter_actor_get_z_rotation_gravity:
10929  * @self: A #ClutterActor
10930  *
10931  * Retrieves the center for the rotation around the Z axis as a
10932  * compass direction. If the center was specified in pixels or units
10933  * this will return %CLUTTER_GRAVITY_NONE.
10934  *
10935  * Return value: the Z rotation center
10936  *
10937  * Since: 1.0
10938  */
10939 ClutterGravity
10940 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10941 {
10942   const ClutterTransformInfo *info;
10943
10944   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10945
10946   info = _clutter_actor_get_transform_info_or_defaults (self);
10947
10948   return clutter_anchor_coord_get_gravity (&info->rz_center);
10949 }
10950
10951 /**
10952  * clutter_actor_set_clip:
10953  * @self: A #ClutterActor
10954  * @xoff: X offset of the clip rectangle
10955  * @yoff: Y offset of the clip rectangle
10956  * @width: Width of the clip rectangle
10957  * @height: Height of the clip rectangle
10958  *
10959  * Sets clip area for @self. The clip area is always computed from the
10960  * upper left corner of the actor, even if the anchor point is set
10961  * otherwise.
10962  *
10963  * Since: 0.6
10964  */
10965 void
10966 clutter_actor_set_clip (ClutterActor *self,
10967                         gfloat        xoff,
10968                         gfloat        yoff,
10969                         gfloat        width,
10970                         gfloat        height)
10971 {
10972   ClutterActorPrivate *priv;
10973
10974   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10975
10976   priv = self->priv;
10977
10978   if (priv->has_clip &&
10979       priv->clip.x == xoff &&
10980       priv->clip.y == yoff &&
10981       priv->clip.width == width &&
10982       priv->clip.height == height)
10983     return;
10984
10985   priv->clip.x = xoff;
10986   priv->clip.y = yoff;
10987   priv->clip.width = width;
10988   priv->clip.height = height;
10989
10990   priv->has_clip = TRUE;
10991
10992   clutter_actor_queue_redraw (self);
10993
10994   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10995   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10996 }
10997
10998 /**
10999  * clutter_actor_remove_clip:
11000  * @self: A #ClutterActor
11001  *
11002  * Removes clip area from @self.
11003  */
11004 void
11005 clutter_actor_remove_clip (ClutterActor *self)
11006 {
11007   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11008
11009   if (!self->priv->has_clip)
11010     return;
11011
11012   self->priv->has_clip = FALSE;
11013
11014   clutter_actor_queue_redraw (self);
11015
11016   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
11017 }
11018
11019 /**
11020  * clutter_actor_has_clip:
11021  * @self: a #ClutterActor
11022  *
11023  * Determines whether the actor has a clip area set or not.
11024  *
11025  * Return value: %TRUE if the actor has a clip area set.
11026  *
11027  * Since: 0.1.1
11028  */
11029 gboolean
11030 clutter_actor_has_clip (ClutterActor *self)
11031 {
11032   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11033
11034   return self->priv->has_clip;
11035 }
11036
11037 /**
11038  * clutter_actor_get_clip:
11039  * @self: a #ClutterActor
11040  * @xoff: (out) (allow-none): return location for the X offset of
11041  *   the clip rectangle, or %NULL
11042  * @yoff: (out) (allow-none): return location for the Y offset of
11043  *   the clip rectangle, or %NULL
11044  * @width: (out) (allow-none): return location for the width of
11045  *   the clip rectangle, or %NULL
11046  * @height: (out) (allow-none): return location for the height of
11047  *   the clip rectangle, or %NULL
11048  *
11049  * Gets the clip area for @self, if any is set
11050  *
11051  * Since: 0.6
11052  */
11053 void
11054 clutter_actor_get_clip (ClutterActor *self,
11055                         gfloat       *xoff,
11056                         gfloat       *yoff,
11057                         gfloat       *width,
11058                         gfloat       *height)
11059 {
11060   ClutterActorPrivate *priv;
11061
11062   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11063
11064   priv = self->priv;
11065
11066   if (!priv->has_clip)
11067     return;
11068
11069   if (xoff != NULL)
11070     *xoff = priv->clip.x;
11071
11072   if (yoff != NULL)
11073     *yoff = priv->clip.y;
11074
11075   if (width != NULL)
11076     *width = priv->clip.width;
11077
11078   if (height != NULL)
11079     *height = priv->clip.height;
11080 }
11081
11082 /**
11083  * clutter_actor_get_children:
11084  * @self: a #ClutterActor
11085  *
11086  * Retrieves the list of children of @self.
11087  *
11088  * Return value: (transfer container) (element-type ClutterActor): A newly
11089  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
11090  *   done.
11091  *
11092  * Since: 1.10
11093  */
11094 GList *
11095 clutter_actor_get_children (ClutterActor *self)
11096 {
11097   ClutterActor *iter;
11098   GList *res;
11099
11100   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11101
11102   /* we walk the list backward so that we can use prepend(),
11103    * which is O(1)
11104    */
11105   for (iter = self->priv->last_child, res = NULL;
11106        iter != NULL;
11107        iter = iter->priv->prev_sibling)
11108     {
11109       res = g_list_prepend (res, iter);
11110     }
11111
11112   return res;
11113 }
11114
11115 /*< private >
11116  * insert_child_at_depth:
11117  * @self: a #ClutterActor
11118  * @child: a #ClutterActor
11119  *
11120  * Inserts @child inside the list of children held by @self, using
11121  * the depth as the insertion criteria.
11122  *
11123  * This sadly makes the insertion not O(1), but we can keep the
11124  * list sorted so that the painters algorithm we use for painting
11125  * the children will work correctly.
11126  */
11127 static void
11128 insert_child_at_depth (ClutterActor *self,
11129                        ClutterActor *child,
11130                        gpointer      dummy G_GNUC_UNUSED)
11131 {
11132   ClutterActor *iter;
11133   float child_depth;
11134
11135   child->priv->parent = self;
11136
11137   child_depth =
11138     _clutter_actor_get_transform_info_or_defaults (child)->depth;
11139
11140   /* special-case the first child */
11141   if (self->priv->n_children == 0)
11142     {
11143       self->priv->first_child = child;
11144       self->priv->last_child = child;
11145
11146       child->priv->next_sibling = NULL;
11147       child->priv->prev_sibling = NULL;
11148
11149       return;
11150     }
11151
11152   /* Find the right place to insert the child so that it will still be
11153      sorted and the child will be after all of the actors at the same
11154      dept */
11155   for (iter = self->priv->first_child;
11156        iter != NULL;
11157        iter = iter->priv->next_sibling)
11158     {
11159       float iter_depth;
11160
11161       iter_depth =
11162         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
11163
11164       if (iter_depth > child_depth)
11165         break;
11166     }
11167
11168   if (iter != NULL)
11169     {
11170       ClutterActor *tmp = iter->priv->prev_sibling;
11171
11172       if (tmp != NULL)
11173         tmp->priv->next_sibling = child;
11174
11175       /* Insert the node before the found one */
11176       child->priv->prev_sibling = iter->priv->prev_sibling;
11177       child->priv->next_sibling = iter;
11178       iter->priv->prev_sibling = child;
11179     }
11180   else
11181     {
11182       ClutterActor *tmp = self->priv->last_child;
11183
11184       if (tmp != NULL)
11185         tmp->priv->next_sibling = child;
11186
11187       /* insert the node at the end of the list */
11188       child->priv->prev_sibling = self->priv->last_child;
11189       child->priv->next_sibling = NULL;
11190     }
11191
11192   if (child->priv->prev_sibling == NULL)
11193     self->priv->first_child = child;
11194
11195   if (child->priv->next_sibling == NULL)
11196     self->priv->last_child = child;
11197 }
11198
11199 static void
11200 insert_child_at_index (ClutterActor *self,
11201                        ClutterActor *child,
11202                        gpointer      data_)
11203 {
11204   gint index_ = GPOINTER_TO_INT (data_);
11205
11206   child->priv->parent = self;
11207
11208   if (index_ == 0)
11209     {
11210       ClutterActor *tmp = self->priv->first_child;
11211
11212       if (tmp != NULL)
11213         tmp->priv->prev_sibling = child;
11214
11215       child->priv->prev_sibling = NULL;
11216       child->priv->next_sibling = tmp;
11217     }
11218   else if (index_ < 0 || index_ >= self->priv->n_children)
11219     {
11220       ClutterActor *tmp = self->priv->last_child;
11221
11222       if (tmp != NULL)
11223         tmp->priv->next_sibling = child;
11224
11225       child->priv->prev_sibling = tmp;
11226       child->priv->next_sibling = NULL;
11227     }
11228   else
11229     {
11230       ClutterActor *iter;
11231       int i;
11232
11233       for (iter = self->priv->first_child, i = 0;
11234            iter != NULL;
11235            iter = iter->priv->next_sibling, i += 1)
11236         {
11237           if (index_ == i)
11238             {
11239               ClutterActor *tmp = iter->priv->prev_sibling;
11240
11241               child->priv->prev_sibling = tmp;
11242               child->priv->next_sibling = iter;
11243
11244               iter->priv->prev_sibling = child;
11245
11246               if (tmp != NULL)
11247                 tmp->priv->next_sibling = child;
11248
11249               break;
11250             }
11251         }
11252     }
11253
11254   if (child->priv->prev_sibling == NULL)
11255     self->priv->first_child = child;
11256
11257   if (child->priv->next_sibling == NULL)
11258     self->priv->last_child = child;
11259 }
11260
11261 static void
11262 insert_child_above (ClutterActor *self,
11263                     ClutterActor *child,
11264                     gpointer      data)
11265 {
11266   ClutterActor *sibling = data;
11267
11268   child->priv->parent = self;
11269
11270   if (sibling == NULL)
11271     sibling = self->priv->last_child;
11272
11273   child->priv->prev_sibling = sibling;
11274
11275   if (sibling != NULL)
11276     {
11277       ClutterActor *tmp = sibling->priv->next_sibling;
11278
11279       child->priv->next_sibling = tmp;
11280
11281       if (tmp != NULL)
11282         tmp->priv->prev_sibling = child;
11283
11284       sibling->priv->next_sibling = child;
11285     }
11286   else
11287     child->priv->next_sibling = NULL;
11288
11289   if (child->priv->prev_sibling == NULL)
11290     self->priv->first_child = child;
11291
11292   if (child->priv->next_sibling == NULL)
11293     self->priv->last_child = child;
11294 }
11295
11296 static void
11297 insert_child_below (ClutterActor *self,
11298                     ClutterActor *child,
11299                     gpointer      data)
11300 {
11301   ClutterActor *sibling = data;
11302
11303   child->priv->parent = self;
11304
11305   if (sibling == NULL)
11306     sibling = self->priv->first_child;
11307
11308   child->priv->next_sibling = sibling;
11309
11310   if (sibling != NULL)
11311     {
11312       ClutterActor *tmp = sibling->priv->prev_sibling;
11313
11314       child->priv->prev_sibling = tmp;
11315
11316       if (tmp != NULL)
11317         tmp->priv->next_sibling = child;
11318
11319       sibling->priv->prev_sibling = child;
11320     }
11321   else
11322     child->priv->prev_sibling = NULL;
11323
11324   if (child->priv->prev_sibling == NULL)
11325     self->priv->first_child = child;
11326
11327   if (child->priv->next_sibling == NULL)
11328     self->priv->last_child = child;
11329 }
11330
11331 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11332                                            ClutterActor *child,
11333                                            gpointer      data);
11334
11335 typedef enum {
11336   ADD_CHILD_CREATE_META        = 1 << 0,
11337   ADD_CHILD_EMIT_PARENT_SET    = 1 << 1,
11338   ADD_CHILD_EMIT_ACTOR_ADDED   = 1 << 2,
11339   ADD_CHILD_CHECK_STATE        = 1 << 3,
11340   ADD_CHILD_NOTIFY_FIRST_LAST  = 1 << 4,
11341   ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11342
11343   /* default flags for public API */
11344   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
11345                                ADD_CHILD_EMIT_PARENT_SET |
11346                                ADD_CHILD_EMIT_ACTOR_ADDED |
11347                                ADD_CHILD_CHECK_STATE |
11348                                ADD_CHILD_NOTIFY_FIRST_LAST |
11349                                ADD_CHILD_SHOW_ON_SET_PARENT,
11350
11351   /* flags for legacy/deprecated API */
11352   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
11353                                ADD_CHILD_CHECK_STATE |
11354                                ADD_CHILD_NOTIFY_FIRST_LAST |
11355                                ADD_CHILD_SHOW_ON_SET_PARENT
11356 } ClutterActorAddChildFlags;
11357
11358 /*< private >
11359  * clutter_actor_add_child_internal:
11360  * @self: a #ClutterActor
11361  * @child: a #ClutterActor
11362  * @flags: control flags for actions
11363  * @add_func: delegate function
11364  * @data: (closure): data to pass to @add_func
11365  *
11366  * Adds @child to the list of children of @self.
11367  *
11368  * The actual insertion inside the list is delegated to @add_func: this
11369  * function will just set up the state, perform basic checks, and emit
11370  * signals.
11371  *
11372  * The @flags argument is used to perform additional operations.
11373  */
11374 static inline void
11375 clutter_actor_add_child_internal (ClutterActor              *self,
11376                                   ClutterActor              *child,
11377                                   ClutterActorAddChildFlags  flags,
11378                                   ClutterActorAddChildFunc   add_func,
11379                                   gpointer                   data)
11380 {
11381   ClutterTextDirection text_dir;
11382   gboolean create_meta;
11383   gboolean emit_parent_set, emit_actor_added;
11384   gboolean check_state;
11385   gboolean notify_first_last;
11386   gboolean show_on_set_parent;
11387   ClutterActor *old_first_child, *old_last_child;
11388
11389   if (child->priv->parent != NULL)
11390     {
11391       g_warning ("The actor '%s' already has a parent, '%s'. You must "
11392                  "use clutter_actor_remove_child() first.",
11393                  _clutter_actor_get_debug_name (child),
11394                  _clutter_actor_get_debug_name (child->priv->parent));
11395       return;
11396     }
11397
11398   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11399     {
11400       g_warning ("The actor '%s' is a top-level actor, and cannot be "
11401                  "a child of another actor.",
11402                  _clutter_actor_get_debug_name (child));
11403       return;
11404     }
11405
11406 #if 0
11407   /* XXX - this check disallows calling methods that change the stacking
11408    * order within the destruction sequence, by triggering a critical
11409    * warning first, and leaving the actor in an undefined state, which
11410    * then ends up being caught by an assertion.
11411    *
11412    * the reproducible sequence is:
11413    *
11414    *   - actor gets destroyed;
11415    *   - another actor, linked to the first, will try to change the
11416    *     stacking order of the first actor;
11417    *   - changing the stacking order is a composite operation composed
11418    *     by the following steps:
11419    *     1. ref() the child;
11420    *     2. remove_child_internal(), which removes the reference;
11421    *     3. add_child_internal(), which adds a reference;
11422    *   - the state of the actor is not changed between (2) and (3), as
11423    *     it could be an expensive recomputation;
11424    *   - if (3) bails out, then the actor is in an undefined state, but
11425    *     still alive;
11426    *   - the destruction sequence terminates, but the actor is unparented
11427    *     while its state indicates being parented instead.
11428    *   - assertion failure.
11429    *
11430    * the obvious fix would be to decompose each set_child_*_sibling()
11431    * method into proper remove_child()/add_child(), with state validation;
11432    * this may cause excessive work, though, and trigger a cascade of other
11433    * bugs in code that assumes that a change in the stacking order is an
11434    * atomic operation.
11435    *
11436    * another potential fix is to just remove this check here, and let
11437    * code doing stacking order changes inside the destruction sequence
11438    * of an actor continue doing the work.
11439    *
11440    * the third fix is to silently bail out early from every
11441    * set_child_*_sibling() and set_child_at_index() method, and avoid
11442    * doing work.
11443    *
11444    * I have a preference for the second solution, since it involves the
11445    * least amount of work, and the least amount of code duplication.
11446    *
11447    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11448    */
11449   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11450     {
11451       g_warning ("The actor '%s' is currently being destroyed, and "
11452                  "cannot be added as a child of another actor.",
11453                  _clutter_actor_get_debug_name (child));
11454       return;
11455     }
11456 #endif
11457
11458   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11459   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11460   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11461   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11462   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11463   show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11464
11465   old_first_child = self->priv->first_child;
11466   old_last_child = self->priv->last_child;
11467
11468   g_object_freeze_notify (G_OBJECT (self));
11469
11470   if (create_meta)
11471     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11472
11473   g_object_ref_sink (child);
11474   child->priv->parent = NULL;
11475   child->priv->next_sibling = NULL;
11476   child->priv->prev_sibling = NULL;
11477
11478   /* delegate the actual insertion */
11479   add_func (self, child, data);
11480
11481   g_assert (child->priv->parent == self);
11482
11483   self->priv->n_children += 1;
11484
11485   self->priv->age += 1;
11486
11487   /* if push_internal() has been called then we automatically set
11488    * the flag on the actor
11489    */
11490   if (self->priv->internal_child)
11491     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11492
11493   /* children may cause their parent to expand, if they are set
11494    * to expand; if a child is not expanded then it cannot change
11495    * its parent's state. any further change later on will queue
11496    * an expand state check.
11497    *
11498    * this check, with the initial state of the needs_compute_expand
11499    * flag set to FALSE, should avoid recomputing the expand flags
11500    * state while building the actor tree.
11501    */
11502   if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
11503       (child->priv->needs_compute_expand ||
11504        child->priv->needs_x_expand ||
11505        child->priv->needs_y_expand))
11506     {
11507       clutter_actor_queue_compute_expand (self);
11508     }
11509
11510   /* clutter_actor_reparent() will emit ::parent-set for us */
11511   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11512     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11513
11514   if (check_state)
11515     {
11516       /* If parent is mapped or realized, we need to also be mapped or
11517        * realized once we're inside the parent.
11518        */
11519       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11520
11521       /* propagate the parent's text direction to the child */
11522       text_dir = clutter_actor_get_text_direction (self);
11523       clutter_actor_set_text_direction (child, text_dir);
11524     }
11525
11526   if (show_on_set_parent && child->priv->show_on_set_parent)
11527     clutter_actor_show (child);
11528
11529   if (CLUTTER_ACTOR_IS_MAPPED (child))
11530     clutter_actor_queue_redraw (child);
11531
11532   /* maintain the invariant that if an actor needs layout,
11533    * its parents do as well
11534    */
11535   if (child->priv->needs_width_request ||
11536       child->priv->needs_height_request ||
11537       child->priv->needs_allocation)
11538     {
11539       /* we work around the short-circuiting we do
11540        * in clutter_actor_queue_relayout() since we
11541        * want to force a relayout
11542        */
11543       child->priv->needs_width_request = TRUE;
11544       child->priv->needs_height_request = TRUE;
11545       child->priv->needs_allocation = TRUE;
11546
11547       clutter_actor_queue_relayout (child->priv->parent);
11548     }
11549
11550   if (emit_actor_added)
11551     g_signal_emit_by_name (self, "actor-added", child);
11552
11553   if (notify_first_last)
11554     {
11555       if (old_first_child != self->priv->first_child)
11556         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11557
11558       if (old_last_child != self->priv->last_child)
11559         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11560     }
11561
11562   g_object_thaw_notify (G_OBJECT (self));
11563 }
11564
11565 /**
11566  * clutter_actor_add_child:
11567  * @self: a #ClutterActor
11568  * @child: a #ClutterActor
11569  *
11570  * Adds @child to the children of @self.
11571  *
11572  * This function will acquire a reference on @child that will only
11573  * be released when calling clutter_actor_remove_child().
11574  *
11575  * This function will take into consideration the #ClutterActor:depth
11576  * of @child, and will keep the list of children sorted.
11577  *
11578  * This function will emit the #ClutterContainer::actor-added signal
11579  * on @self.
11580  *
11581  * Since: 1.10
11582  */
11583 void
11584 clutter_actor_add_child (ClutterActor *self,
11585                          ClutterActor *child)
11586 {
11587   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11588   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11589   g_return_if_fail (self != child);
11590   g_return_if_fail (child->priv->parent == NULL);
11591
11592   clutter_actor_add_child_internal (self, child,
11593                                     ADD_CHILD_DEFAULT_FLAGS,
11594                                     insert_child_at_depth,
11595                                     NULL);
11596 }
11597
11598 /**
11599  * clutter_actor_insert_child_at_index:
11600  * @self: a #ClutterActor
11601  * @child: a #ClutterActor
11602  * @index_: the index
11603  *
11604  * Inserts @child into the list of children of @self, using the
11605  * given @index_. If @index_ is greater than the number of children
11606  * in @self, or is less than 0, then the new child is added at the end.
11607  *
11608  * This function will acquire a reference on @child that will only
11609  * be released when calling clutter_actor_remove_child().
11610  *
11611  * This function will not take into consideration the #ClutterActor:depth
11612  * of @child.
11613  *
11614  * This function will emit the #ClutterContainer::actor-added signal
11615  * on @self.
11616  *
11617  * Since: 1.10
11618  */
11619 void
11620 clutter_actor_insert_child_at_index (ClutterActor *self,
11621                                      ClutterActor *child,
11622                                      gint          index_)
11623 {
11624   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11625   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11626   g_return_if_fail (self != child);
11627   g_return_if_fail (child->priv->parent == NULL);
11628
11629   clutter_actor_add_child_internal (self, child,
11630                                     ADD_CHILD_DEFAULT_FLAGS,
11631                                     insert_child_at_index,
11632                                     GINT_TO_POINTER (index_));
11633 }
11634
11635 /**
11636  * clutter_actor_insert_child_above:
11637  * @self: a #ClutterActor
11638  * @child: a #ClutterActor
11639  * @sibling: (allow-none): a child of @self, or %NULL
11640  *
11641  * Inserts @child into the list of children of @self, above another
11642  * child of @self or, if @sibling is %NULL, above all the children
11643  * of @self.
11644  *
11645  * This function will acquire a reference on @child that will only
11646  * be released when calling clutter_actor_remove_child().
11647  *
11648  * This function will not take into consideration the #ClutterActor:depth
11649  * of @child.
11650  *
11651  * This function will emit the #ClutterContainer::actor-added signal
11652  * on @self.
11653  *
11654  * Since: 1.10
11655  */
11656 void
11657 clutter_actor_insert_child_above (ClutterActor *self,
11658                                   ClutterActor *child,
11659                                   ClutterActor *sibling)
11660 {
11661   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11662   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11663   g_return_if_fail (self != child);
11664   g_return_if_fail (child != sibling);
11665   g_return_if_fail (child->priv->parent == NULL);
11666   g_return_if_fail (sibling == NULL ||
11667                     (CLUTTER_IS_ACTOR (sibling) &&
11668                      sibling->priv->parent == self));
11669
11670   clutter_actor_add_child_internal (self, child,
11671                                     ADD_CHILD_DEFAULT_FLAGS,
11672                                     insert_child_above,
11673                                     sibling);
11674 }
11675
11676 /**
11677  * clutter_actor_insert_child_below:
11678  * @self: a #ClutterActor
11679  * @child: a #ClutterActor
11680  * @sibling: (allow-none): a child of @self, or %NULL
11681  *
11682  * Inserts @child into the list of children of @self, below another
11683  * child of @self or, if @sibling is %NULL, below all the children
11684  * of @self.
11685  *
11686  * This function will acquire a reference on @child that will only
11687  * be released when calling clutter_actor_remove_child().
11688  *
11689  * This function will not take into consideration the #ClutterActor:depth
11690  * of @child.
11691  *
11692  * This function will emit the #ClutterContainer::actor-added signal
11693  * on @self.
11694  *
11695  * Since: 1.10
11696  */
11697 void
11698 clutter_actor_insert_child_below (ClutterActor *self,
11699                                   ClutterActor *child,
11700                                   ClutterActor *sibling)
11701 {
11702   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11703   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11704   g_return_if_fail (self != child);
11705   g_return_if_fail (child != sibling);
11706   g_return_if_fail (child->priv->parent == NULL);
11707   g_return_if_fail (sibling == NULL ||
11708                     (CLUTTER_IS_ACTOR (sibling) &&
11709                      sibling->priv->parent == self));
11710
11711   clutter_actor_add_child_internal (self, child,
11712                                     ADD_CHILD_DEFAULT_FLAGS,
11713                                     insert_child_below,
11714                                     sibling);
11715 }
11716
11717 /**
11718  * clutter_actor_set_parent:
11719  * @self: A #ClutterActor
11720  * @parent: A new #ClutterActor parent
11721  *
11722  * Sets the parent of @self to @parent.
11723  *
11724  * This function will result in @parent acquiring a reference on @self,
11725  * eventually by sinking its floating reference first. The reference
11726  * will be released by clutter_actor_unparent().
11727  *
11728  * This function should only be called by legacy #ClutterActor<!-- -->s
11729  * implementing the #ClutterContainer interface.
11730  *
11731  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11732  */
11733 void
11734 clutter_actor_set_parent (ClutterActor *self,
11735                           ClutterActor *parent)
11736 {
11737   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11738   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11739   g_return_if_fail (self != parent);
11740   g_return_if_fail (self->priv->parent == NULL);
11741
11742   /* as this function will be called inside ClutterContainer::add
11743    * implementations or when building up a composite actor, we have
11744    * to preserve the old behaviour, and not create child meta or
11745    * emit the ::actor-added signal, to avoid recursion or double
11746    * emissions
11747    */
11748   clutter_actor_add_child_internal (parent, self,
11749                                     ADD_CHILD_LEGACY_FLAGS,
11750                                     insert_child_at_depth,
11751                                     NULL);
11752 }
11753
11754 /**
11755  * clutter_actor_get_parent:
11756  * @self: A #ClutterActor
11757  *
11758  * Retrieves the parent of @self.
11759  *
11760  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11761  *  if no parent is set
11762  */
11763 ClutterActor *
11764 clutter_actor_get_parent (ClutterActor *self)
11765 {
11766   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11767
11768   return self->priv->parent;
11769 }
11770
11771 /**
11772  * clutter_actor_get_paint_visibility:
11773  * @self: A #ClutterActor
11774  *
11775  * Retrieves the 'paint' visibility of an actor recursively checking for non
11776  * visible parents.
11777  *
11778  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11779  *
11780  * Return Value: %TRUE if the actor is visibile and will be painted.
11781  *
11782  * Since: 0.8.4
11783  */
11784 gboolean
11785 clutter_actor_get_paint_visibility (ClutterActor *actor)
11786 {
11787   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11788
11789   return CLUTTER_ACTOR_IS_MAPPED (actor);
11790 }
11791
11792 /**
11793  * clutter_actor_remove_child:
11794  * @self: a #ClutterActor
11795  * @child: a #ClutterActor
11796  *
11797  * Removes @child from the children of @self.
11798  *
11799  * This function will release the reference added by
11800  * clutter_actor_add_child(), so if you want to keep using @child
11801  * you will have to acquire a referenced on it before calling this
11802  * function.
11803  *
11804  * This function will emit the #ClutterContainer::actor-removed
11805  * signal on @self.
11806  *
11807  * Since: 1.10
11808  */
11809 void
11810 clutter_actor_remove_child (ClutterActor *self,
11811                             ClutterActor *child)
11812 {
11813   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11814   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11815   g_return_if_fail (self != child);
11816   g_return_if_fail (child->priv->parent != NULL);
11817   g_return_if_fail (child->priv->parent == self);
11818
11819   clutter_actor_remove_child_internal (self, child,
11820                                        REMOVE_CHILD_DEFAULT_FLAGS);
11821 }
11822
11823 /**
11824  * clutter_actor_remove_all_children:
11825  * @self: a #ClutterActor
11826  *
11827  * Removes all children of @self.
11828  *
11829  * This function releases the reference added by inserting a child actor
11830  * in the list of children of @self.
11831  *
11832  * If the reference count of a child drops to zero, the child will be
11833  * destroyed. If you want to ensure the destruction of all the children
11834  * of @self, use clutter_actor_destroy_all_children().
11835  *
11836  * Since: 1.10
11837  */
11838 void
11839 clutter_actor_remove_all_children (ClutterActor *self)
11840 {
11841   ClutterActorIter iter;
11842
11843   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11844
11845   if (self->priv->n_children == 0)
11846     return;
11847
11848   g_object_freeze_notify (G_OBJECT (self));
11849
11850   clutter_actor_iter_init (&iter, self);
11851   while (clutter_actor_iter_next (&iter, NULL))
11852     clutter_actor_iter_remove (&iter);
11853
11854   g_object_thaw_notify (G_OBJECT (self));
11855
11856   /* sanity check */
11857   g_assert (self->priv->first_child == NULL);
11858   g_assert (self->priv->last_child == NULL);
11859   g_assert (self->priv->n_children == 0);
11860 }
11861
11862 /**
11863  * clutter_actor_destroy_all_children:
11864  * @self: a #ClutterActor
11865  *
11866  * Destroys all children of @self.
11867  *
11868  * This function releases the reference added by inserting a child
11869  * actor in the list of children of @self, and ensures that the
11870  * #ClutterActor::destroy signal is emitted on each child of the
11871  * actor.
11872  *
11873  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11874  * when its reference count drops to 0; the default handler of the
11875  * #ClutterActor::destroy signal will destroy all the children of an
11876  * actor. This function ensures that all children are destroyed, instead
11877  * of just removed from @self, unlike clutter_actor_remove_all_children()
11878  * which will merely release the reference and remove each child.
11879  *
11880  * Unless you acquired an additional reference on each child of @self
11881  * prior to calling clutter_actor_remove_all_children() and want to reuse
11882  * the actors, you should use clutter_actor_destroy_all_children() in
11883  * order to make sure that children are destroyed and signal handlers
11884  * are disconnected even in cases where circular references prevent this
11885  * from automatically happening through reference counting alone.
11886  *
11887  * Since: 1.10
11888  */
11889 void
11890 clutter_actor_destroy_all_children (ClutterActor *self)
11891 {
11892   ClutterActorIter iter;
11893
11894   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11895
11896   if (self->priv->n_children == 0)
11897     return;
11898
11899   g_object_freeze_notify (G_OBJECT (self));
11900
11901   clutter_actor_iter_init (&iter, self);
11902   while (clutter_actor_iter_next (&iter, NULL))
11903     clutter_actor_iter_destroy (&iter);
11904
11905   g_object_thaw_notify (G_OBJECT (self));
11906
11907   /* sanity check */
11908   g_assert (self->priv->first_child == NULL);
11909   g_assert (self->priv->last_child == NULL);
11910   g_assert (self->priv->n_children == 0);
11911 }
11912
11913 typedef struct _InsertBetweenData {
11914   ClutterActor *prev_sibling;
11915   ClutterActor *next_sibling;
11916 } InsertBetweenData;
11917
11918 static void
11919 insert_child_between (ClutterActor *self,
11920                       ClutterActor *child,
11921                       gpointer      data_)
11922 {
11923   InsertBetweenData *data = data_;
11924   ClutterActor *prev_sibling = data->prev_sibling;
11925   ClutterActor *next_sibling = data->next_sibling;
11926
11927   child->priv->parent = self;
11928   child->priv->prev_sibling = prev_sibling;
11929   child->priv->next_sibling = next_sibling;
11930
11931   if (prev_sibling != NULL)
11932     prev_sibling->priv->next_sibling = child;
11933
11934   if (next_sibling != NULL)
11935     next_sibling->priv->prev_sibling = child;
11936
11937   if (child->priv->prev_sibling == NULL)
11938     self->priv->first_child = child;
11939
11940   if (child->priv->next_sibling == NULL)
11941     self->priv->last_child = child;
11942 }
11943
11944 /**
11945  * clutter_actor_replace_child:
11946  * @self: a #ClutterActor
11947  * @old_child: the child of @self to replace
11948  * @new_child: the #ClutterActor to replace @old_child
11949  *
11950  * Replaces @old_child with @new_child in the list of children of @self.
11951  *
11952  * Since: 1.10
11953  */
11954 void
11955 clutter_actor_replace_child (ClutterActor *self,
11956                              ClutterActor *old_child,
11957                              ClutterActor *new_child)
11958 {
11959   ClutterActor *prev_sibling, *next_sibling;
11960   InsertBetweenData clos;
11961
11962   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11963   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11964   g_return_if_fail (old_child->priv->parent == self);
11965   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11966   g_return_if_fail (old_child != new_child);
11967   g_return_if_fail (new_child != self);
11968   g_return_if_fail (new_child->priv->parent == NULL);
11969
11970   prev_sibling = old_child->priv->prev_sibling;
11971   next_sibling = old_child->priv->next_sibling;
11972   clutter_actor_remove_child_internal (self, old_child,
11973                                        REMOVE_CHILD_DEFAULT_FLAGS);
11974
11975   clos.prev_sibling = prev_sibling;
11976   clos.next_sibling = next_sibling;
11977   clutter_actor_add_child_internal (self, new_child,
11978                                     ADD_CHILD_DEFAULT_FLAGS,
11979                                     insert_child_between,
11980                                     &clos);
11981 }
11982
11983 /**
11984  * clutter_actor_unparent:
11985  * @self: a #ClutterActor
11986  *
11987  * Removes the parent of @self.
11988  *
11989  * This will cause the parent of @self to release the reference
11990  * acquired when calling clutter_actor_set_parent(), so if you
11991  * want to keep @self you will have to acquire a reference of
11992  * your own, through g_object_ref().
11993  *
11994  * This function should only be called by legacy #ClutterActor<!-- -->s
11995  * implementing the #ClutterContainer interface.
11996  *
11997  * Since: 0.1.1
11998  *
11999  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
12000  */
12001 void
12002 clutter_actor_unparent (ClutterActor *self)
12003 {
12004   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12005
12006   if (self->priv->parent == NULL)
12007     return;
12008
12009   clutter_actor_remove_child_internal (self->priv->parent, self,
12010                                        REMOVE_CHILD_LEGACY_FLAGS);
12011 }
12012
12013 /**
12014  * clutter_actor_reparent:
12015  * @self: a #ClutterActor
12016  * @new_parent: the new #ClutterActor parent
12017  *
12018  * Resets the parent actor of @self.
12019  *
12020  * This function is logically equivalent to calling clutter_actor_unparent()
12021  * and clutter_actor_set_parent(), but more efficiently implemented, as it
12022  * ensures the child is not finalized when unparented, and emits the
12023  * #ClutterActor::parent-set signal only once.
12024  *
12025  * In reality, calling this function is less useful than it sounds, as some
12026  * application code may rely on changes in the intermediate state between
12027  * removal and addition of the actor from its old parent to the @new_parent.
12028  * Thus, it is strongly encouraged to avoid using this function in application
12029  * code.
12030  *
12031  * Since: 0.2
12032  *
12033  * Deprecated: 1.10: Use clutter_actor_remove_child() and
12034  *   clutter_actor_add_child() instead; remember to take a reference on
12035  *   the actor being removed before calling clutter_actor_remove_child()
12036  *   to avoid the reference count dropping to zero and the actor being
12037  *   destroyed.
12038  */
12039 void
12040 clutter_actor_reparent (ClutterActor *self,
12041                         ClutterActor *new_parent)
12042 {
12043   ClutterActorPrivate *priv;
12044
12045   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12046   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
12047   g_return_if_fail (self != new_parent);
12048
12049   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
12050     {
12051       g_warning ("Cannot set a parent on a toplevel actor");
12052       return;
12053     }
12054
12055   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
12056     {
12057       g_warning ("Cannot set a parent currently being destroyed");
12058       return;
12059     }
12060
12061   priv = self->priv;
12062
12063   if (priv->parent != new_parent)
12064     {
12065       ClutterActor *old_parent;
12066
12067       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12068
12069       old_parent = priv->parent;
12070
12071       g_object_ref (self);
12072
12073       if (old_parent != NULL)
12074         {
12075          /* go through the Container implementation if this is a regular
12076           * child and not an internal one
12077           */
12078          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12079            {
12080              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
12081
12082              /* this will have to call unparent() */
12083              clutter_container_remove_actor (parent, self);
12084            }
12085          else
12086            clutter_actor_remove_child_internal (old_parent, self,
12087                                                 REMOVE_CHILD_LEGACY_FLAGS);
12088         }
12089
12090       /* Note, will call set_parent() */
12091       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
12092         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
12093       else
12094         clutter_actor_add_child_internal (new_parent, self,
12095                                           ADD_CHILD_LEGACY_FLAGS,
12096                                           insert_child_at_depth,
12097                                           NULL);
12098
12099       /* we emit the ::parent-set signal once */
12100       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
12101
12102       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
12103
12104       /* the IN_REPARENT flag suspends state updates */
12105       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
12106
12107       g_object_unref (self);
12108    }
12109 }
12110
12111 /**
12112  * clutter_actor_contains:
12113  * @self: A #ClutterActor
12114  * @descendant: A #ClutterActor, possibly contained in @self
12115  *
12116  * Determines if @descendant is contained inside @self (either as an
12117  * immediate child, or as a deeper descendant). If @self and
12118  * @descendant point to the same actor then it will also return %TRUE.
12119  *
12120  * Return value: whether @descendent is contained within @self
12121  *
12122  * Since: 1.4
12123  */
12124 gboolean
12125 clutter_actor_contains (ClutterActor *self,
12126                         ClutterActor *descendant)
12127 {
12128   ClutterActor *actor;
12129
12130   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
12131   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
12132
12133   for (actor = descendant; actor; actor = actor->priv->parent)
12134     if (actor == self)
12135       return TRUE;
12136
12137   return FALSE;
12138 }
12139
12140 /**
12141  * clutter_actor_set_child_above_sibling:
12142  * @self: a #ClutterActor
12143  * @child: a #ClutterActor child of @self
12144  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12145  *
12146  * Sets @child to be above @sibling in the list of children of @self.
12147  *
12148  * If @sibling is %NULL, @child will be the new last child of @self.
12149  *
12150  * This function is logically equivalent to removing @child and using
12151  * clutter_actor_insert_child_above(), but it will not emit signals
12152  * or change state on @child.
12153  *
12154  * Since: 1.10
12155  */
12156 void
12157 clutter_actor_set_child_above_sibling (ClutterActor *self,
12158                                        ClutterActor *child,
12159                                        ClutterActor *sibling)
12160 {
12161   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12162   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12163   g_return_if_fail (child->priv->parent == self);
12164   g_return_if_fail (child != sibling);
12165   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12166
12167   if (sibling != NULL)
12168     g_return_if_fail (sibling->priv->parent == self);
12169
12170   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12171       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12172       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12173     return;
12174
12175   /* we don't want to change the state of child, or emit signals, or
12176    * regenerate ChildMeta instances here, but we still want to follow
12177    * the correct sequence of steps encoded in remove_child() and
12178    * add_child(), so that correctness is ensured, and we only go
12179    * through one known code path.
12180    */
12181   g_object_ref (child);
12182   clutter_actor_remove_child_internal (self, child, 0);
12183   clutter_actor_add_child_internal (self, child,
12184                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12185                                     insert_child_above,
12186                                     sibling);
12187
12188   clutter_actor_queue_relayout (self);
12189 }
12190
12191 /**
12192  * clutter_actor_set_child_below_sibling:
12193  * @self: a #ClutterActor
12194  * @child: a #ClutterActor child of @self
12195  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
12196  *
12197  * Sets @child to be below @sibling in the list of children of @self.
12198  *
12199  * If @sibling is %NULL, @child will be the new first child of @self.
12200  *
12201  * This function is logically equivalent to removing @self and using
12202  * clutter_actor_insert_child_below(), but it will not emit signals
12203  * or change state on @child.
12204  *
12205  * Since: 1.10
12206  */
12207 void
12208 clutter_actor_set_child_below_sibling (ClutterActor *self,
12209                                        ClutterActor *child,
12210                                        ClutterActor *sibling)
12211 {
12212   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12213   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12214   g_return_if_fail (child->priv->parent == self);
12215   g_return_if_fail (child != sibling);
12216   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
12217
12218   if (sibling != NULL)
12219     g_return_if_fail (sibling->priv->parent == self);
12220
12221   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12222       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
12223       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
12224     return;
12225
12226   /* see the comment in set_child_above_sibling() */
12227   g_object_ref (child);
12228   clutter_actor_remove_child_internal (self, child, 0);
12229   clutter_actor_add_child_internal (self, child,
12230                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12231                                     insert_child_below,
12232                                     sibling);
12233
12234   clutter_actor_queue_relayout (self);
12235 }
12236
12237 /**
12238  * clutter_actor_set_child_at_index:
12239  * @self: a #ClutterActor
12240  * @child: a #ClutterActor child of @self
12241  * @index_: the new index for @child
12242  *
12243  * Changes the index of @child in the list of children of @self.
12244  *
12245  * This function is logically equivalent to removing @child and
12246  * calling clutter_actor_insert_child_at_index(), but it will not
12247  * emit signals or change state on @child.
12248  *
12249  * Since: 1.10
12250  */
12251 void
12252 clutter_actor_set_child_at_index (ClutterActor *self,
12253                                   ClutterActor *child,
12254                                   gint          index_)
12255 {
12256   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12257   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12258   g_return_if_fail (child->priv->parent == self);
12259   g_return_if_fail (index_ <= self->priv->n_children);
12260
12261   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12262       CLUTTER_ACTOR_IN_DESTRUCTION (child))
12263     return;
12264
12265   g_object_ref (child);
12266   clutter_actor_remove_child_internal (self, child, 0);
12267   clutter_actor_add_child_internal (self, child,
12268                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12269                                     insert_child_at_index,
12270                                     GINT_TO_POINTER (index_));
12271
12272   clutter_actor_queue_relayout (self);
12273 }
12274
12275 /**
12276  * clutter_actor_raise:
12277  * @self: A #ClutterActor
12278  * @below: (allow-none): A #ClutterActor to raise above.
12279  *
12280  * Puts @self above @below.
12281  *
12282  * Both actors must have the same parent, and the parent must implement
12283  * the #ClutterContainer interface
12284  *
12285  * This function calls clutter_container_raise_child() internally.
12286  *
12287  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12288  */
12289 void
12290 clutter_actor_raise (ClutterActor *self,
12291                      ClutterActor *below)
12292 {
12293   ClutterActor *parent;
12294
12295   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12296
12297   parent = clutter_actor_get_parent (self);
12298   if (parent == NULL)
12299     {
12300       g_warning ("%s: Actor '%s' is not inside a container",
12301                  G_STRFUNC,
12302                  _clutter_actor_get_debug_name (self));
12303       return;
12304     }
12305
12306   if (below != NULL)
12307     {
12308       if (parent != clutter_actor_get_parent (below))
12309         {
12310           g_warning ("%s Actor '%s' is not in the same container as "
12311                      "actor '%s'",
12312                      G_STRFUNC,
12313                      _clutter_actor_get_debug_name (self),
12314                      _clutter_actor_get_debug_name (below));
12315           return;
12316         }
12317     }
12318
12319   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12320 }
12321
12322 /**
12323  * clutter_actor_lower:
12324  * @self: A #ClutterActor
12325  * @above: (allow-none): A #ClutterActor to lower below
12326  *
12327  * Puts @self below @above.
12328  *
12329  * Both actors must have the same parent, and the parent must implement
12330  * the #ClutterContainer interface.
12331  *
12332  * This function calls clutter_container_lower_child() internally.
12333  *
12334  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12335  */
12336 void
12337 clutter_actor_lower (ClutterActor *self,
12338                      ClutterActor *above)
12339 {
12340   ClutterActor *parent;
12341
12342   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12343
12344   parent = clutter_actor_get_parent (self);
12345   if (parent == NULL)
12346     {
12347       g_warning ("%s: Actor of type %s is not inside a container",
12348                  G_STRFUNC,
12349                  _clutter_actor_get_debug_name (self));
12350       return;
12351     }
12352
12353   if (above)
12354     {
12355       if (parent != clutter_actor_get_parent (above))
12356         {
12357           g_warning ("%s: Actor '%s' is not in the same container as "
12358                      "actor '%s'",
12359                      G_STRFUNC,
12360                      _clutter_actor_get_debug_name (self),
12361                      _clutter_actor_get_debug_name (above));
12362           return;
12363         }
12364     }
12365
12366   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12367 }
12368
12369 /**
12370  * clutter_actor_raise_top:
12371  * @self: A #ClutterActor
12372  *
12373  * Raises @self to the top.
12374  *
12375  * This function calls clutter_actor_raise() internally.
12376  *
12377  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12378  *   a %NULL sibling, instead.
12379  */
12380 void
12381 clutter_actor_raise_top (ClutterActor *self)
12382 {
12383   clutter_actor_raise (self, NULL);
12384 }
12385
12386 /**
12387  * clutter_actor_lower_bottom:
12388  * @self: A #ClutterActor
12389  *
12390  * Lowers @self to the bottom.
12391  *
12392  * This function calls clutter_actor_lower() internally.
12393  *
12394  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12395  *   a %NULL sibling, instead.
12396  */
12397 void
12398 clutter_actor_lower_bottom (ClutterActor *self)
12399 {
12400   clutter_actor_lower (self, NULL);
12401 }
12402
12403 /*
12404  * Event handling
12405  */
12406
12407 /**
12408  * clutter_actor_event:
12409  * @actor: a #ClutterActor
12410  * @event: a #ClutterEvent
12411  * @capture: TRUE if event in in capture phase, FALSE otherwise.
12412  *
12413  * This function is used to emit an event on the main stage.
12414  * You should rarely need to use this function, except for
12415  * synthetising events.
12416  *
12417  * Return value: the return value from the signal emission: %TRUE
12418  *   if the actor handled the event, or %FALSE if the event was
12419  *   not handled
12420  *
12421  * Since: 0.6
12422  */
12423 gboolean
12424 clutter_actor_event (ClutterActor *actor,
12425                      ClutterEvent *event,
12426                      gboolean      capture)
12427 {
12428   gboolean retval = FALSE;
12429   gint signal_num = -1;
12430
12431   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12432   g_return_val_if_fail (event != NULL, FALSE);
12433
12434   g_object_ref (actor);
12435
12436   if (capture)
12437     {
12438       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12439                      event,
12440                      &retval);
12441       goto out;
12442     }
12443
12444   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12445
12446   if (!retval)
12447     {
12448       switch (event->type)
12449         {
12450         case CLUTTER_NOTHING:
12451           break;
12452         case CLUTTER_BUTTON_PRESS:
12453           signal_num = BUTTON_PRESS_EVENT;
12454           break;
12455         case CLUTTER_BUTTON_RELEASE:
12456           signal_num = BUTTON_RELEASE_EVENT;
12457           break;
12458         case CLUTTER_SCROLL:
12459           signal_num = SCROLL_EVENT;
12460           break;
12461         case CLUTTER_KEY_PRESS:
12462           signal_num = KEY_PRESS_EVENT;
12463           break;
12464         case CLUTTER_KEY_RELEASE:
12465           signal_num = KEY_RELEASE_EVENT;
12466           break;
12467         case CLUTTER_MOTION:
12468           signal_num = MOTION_EVENT;
12469           break;
12470         case CLUTTER_ENTER:
12471           signal_num = ENTER_EVENT;
12472           break;
12473         case CLUTTER_LEAVE:
12474           signal_num = LEAVE_EVENT;
12475           break;
12476         case CLUTTER_DELETE:
12477         case CLUTTER_DESTROY_NOTIFY:
12478         case CLUTTER_CLIENT_MESSAGE:
12479         default:
12480           signal_num = -1;
12481           break;
12482         }
12483
12484       if (signal_num != -1)
12485         g_signal_emit (actor, actor_signals[signal_num], 0,
12486                        event, &retval);
12487     }
12488
12489 out:
12490   g_object_unref (actor);
12491
12492   return retval;
12493 }
12494
12495 /**
12496  * clutter_actor_set_reactive:
12497  * @actor: a #ClutterActor
12498  * @reactive: whether the actor should be reactive to events
12499  *
12500  * Sets @actor as reactive. Reactive actors will receive events.
12501  *
12502  * Since: 0.6
12503  */
12504 void
12505 clutter_actor_set_reactive (ClutterActor *actor,
12506                             gboolean      reactive)
12507 {
12508   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12509
12510   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12511     return;
12512
12513   if (reactive)
12514     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12515   else
12516     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12517
12518   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12519 }
12520
12521 /**
12522  * clutter_actor_get_reactive:
12523  * @actor: a #ClutterActor
12524  *
12525  * Checks whether @actor is marked as reactive.
12526  *
12527  * Return value: %TRUE if the actor is reactive
12528  *
12529  * Since: 0.6
12530  */
12531 gboolean
12532 clutter_actor_get_reactive (ClutterActor *actor)
12533 {
12534   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12535
12536   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12537 }
12538
12539 /**
12540  * clutter_actor_get_anchor_point:
12541  * @self: a #ClutterActor
12542  * @anchor_x: (out): return location for the X coordinate of the anchor point
12543  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12544  *
12545  * Gets the current anchor point of the @actor in pixels.
12546  *
12547  * Since: 0.6
12548  */
12549 void
12550 clutter_actor_get_anchor_point (ClutterActor *self,
12551                                 gfloat       *anchor_x,
12552                                 gfloat       *anchor_y)
12553 {
12554   const ClutterTransformInfo *info;
12555
12556   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12557
12558   info = _clutter_actor_get_transform_info_or_defaults (self);
12559   clutter_anchor_coord_get_units (self, &info->anchor,
12560                                   anchor_x,
12561                                   anchor_y,
12562                                   NULL);
12563 }
12564
12565 /**
12566  * clutter_actor_set_anchor_point:
12567  * @self: a #ClutterActor
12568  * @anchor_x: X coordinate of the anchor point
12569  * @anchor_y: Y coordinate of the anchor point
12570  *
12571  * Sets an anchor point for @self. The anchor point is a point in the
12572  * coordinate space of an actor to which the actor position within its
12573  * parent is relative; the default is (0, 0), i.e. the top-left corner
12574  * of the actor.
12575  *
12576  * Since: 0.6
12577  */
12578 void
12579 clutter_actor_set_anchor_point (ClutterActor *self,
12580                                 gfloat        anchor_x,
12581                                 gfloat        anchor_y)
12582 {
12583   ClutterTransformInfo *info;
12584   ClutterActorPrivate *priv;
12585   gboolean changed = FALSE;
12586   gfloat old_anchor_x, old_anchor_y;
12587   GObject *obj;
12588
12589   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12590
12591   obj = G_OBJECT (self);
12592   priv = self->priv;
12593   info = _clutter_actor_get_transform_info (self);
12594
12595   g_object_freeze_notify (obj);
12596
12597   clutter_anchor_coord_get_units (self, &info->anchor,
12598                                   &old_anchor_x,
12599                                   &old_anchor_y,
12600                                   NULL);
12601
12602   if (info->anchor.is_fractional)
12603     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12604
12605   if (old_anchor_x != anchor_x)
12606     {
12607       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12608       changed = TRUE;
12609     }
12610
12611   if (old_anchor_y != anchor_y)
12612     {
12613       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12614       changed = TRUE;
12615     }
12616
12617   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12618
12619   if (changed)
12620     {
12621       priv->transform_valid = FALSE;
12622       clutter_actor_queue_redraw (self);
12623     }
12624
12625   g_object_thaw_notify (obj);
12626 }
12627
12628 /**
12629  * clutter_actor_get_anchor_point_gravity:
12630  * @self: a #ClutterActor
12631  *
12632  * Retrieves the anchor position expressed as a #ClutterGravity. If
12633  * the anchor point was specified using pixels or units this will
12634  * return %CLUTTER_GRAVITY_NONE.
12635  *
12636  * Return value: the #ClutterGravity used by the anchor point
12637  *
12638  * Since: 1.0
12639  */
12640 ClutterGravity
12641 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12642 {
12643   const ClutterTransformInfo *info;
12644
12645   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12646
12647   info = _clutter_actor_get_transform_info_or_defaults (self);
12648
12649   return clutter_anchor_coord_get_gravity (&info->anchor);
12650 }
12651
12652 /**
12653  * clutter_actor_move_anchor_point:
12654  * @self: a #ClutterActor
12655  * @anchor_x: X coordinate of the anchor point
12656  * @anchor_y: Y coordinate of the anchor point
12657  *
12658  * Sets an anchor point for the actor, and adjusts the actor postion so that
12659  * the relative position of the actor toward its parent remains the same.
12660  *
12661  * Since: 0.6
12662  */
12663 void
12664 clutter_actor_move_anchor_point (ClutterActor *self,
12665                                  gfloat        anchor_x,
12666                                  gfloat        anchor_y)
12667 {
12668   gfloat old_anchor_x, old_anchor_y;
12669   const ClutterTransformInfo *info;
12670
12671   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12672
12673   info = _clutter_actor_get_transform_info (self);
12674   clutter_anchor_coord_get_units (self, &info->anchor,
12675                                   &old_anchor_x,
12676                                   &old_anchor_y,
12677                                   NULL);
12678
12679   g_object_freeze_notify (G_OBJECT (self));
12680
12681   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12682
12683   if (self->priv->position_set)
12684     clutter_actor_move_by (self,
12685                            anchor_x - old_anchor_x,
12686                            anchor_y - old_anchor_y);
12687
12688   g_object_thaw_notify (G_OBJECT (self));
12689 }
12690
12691 /**
12692  * clutter_actor_move_anchor_point_from_gravity:
12693  * @self: a #ClutterActor
12694  * @gravity: #ClutterGravity.
12695  *
12696  * Sets an anchor point on the actor based on the given gravity, adjusting the
12697  * actor postion so that its relative position within its parent remains
12698  * unchanged.
12699  *
12700  * Since version 1.0 the anchor point will be stored as a gravity so
12701  * that if the actor changes size then the anchor point will move. For
12702  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12703  * and later double the size of the actor, the anchor point will move
12704  * to the bottom right.
12705  *
12706  * Since: 0.6
12707  */
12708 void
12709 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12710                                               ClutterGravity  gravity)
12711 {
12712   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12713   const ClutterTransformInfo *info;
12714   ClutterActorPrivate *priv;
12715
12716   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12717
12718   priv = self->priv;
12719   info = _clutter_actor_get_transform_info (self);
12720
12721   g_object_freeze_notify (G_OBJECT (self));
12722
12723   clutter_anchor_coord_get_units (self, &info->anchor,
12724                                   &old_anchor_x,
12725                                   &old_anchor_y,
12726                                   NULL);
12727   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12728   clutter_anchor_coord_get_units (self, &info->anchor,
12729                                   &new_anchor_x,
12730                                   &new_anchor_y,
12731                                   NULL);
12732
12733   if (priv->position_set)
12734     clutter_actor_move_by (self,
12735                            new_anchor_x - old_anchor_x,
12736                            new_anchor_y - old_anchor_y);
12737
12738   g_object_thaw_notify (G_OBJECT (self));
12739 }
12740
12741 /**
12742  * clutter_actor_set_anchor_point_from_gravity:
12743  * @self: a #ClutterActor
12744  * @gravity: #ClutterGravity.
12745  *
12746  * Sets an anchor point on the actor, based on the given gravity (this is a
12747  * convenience function wrapping clutter_actor_set_anchor_point()).
12748  *
12749  * Since version 1.0 the anchor point will be stored as a gravity so
12750  * that if the actor changes size then the anchor point will move. For
12751  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12752  * and later double the size of the actor, the anchor point will move
12753  * to the bottom right.
12754  *
12755  * Since: 0.6
12756  */
12757 void
12758 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12759                                              ClutterGravity  gravity)
12760 {
12761   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12762
12763   if (gravity == CLUTTER_GRAVITY_NONE)
12764     clutter_actor_set_anchor_point (self, 0, 0);
12765   else
12766     {
12767       GObject *obj = G_OBJECT (self);
12768       ClutterTransformInfo *info;
12769
12770       g_object_freeze_notify (obj);
12771
12772       info = _clutter_actor_get_transform_info (self);
12773       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12774
12775       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12776       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12777       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12778
12779       self->priv->transform_valid = FALSE;
12780
12781       clutter_actor_queue_redraw (self);
12782
12783       g_object_thaw_notify (obj);
12784     }
12785 }
12786
12787 static void
12788 clutter_actor_store_content_box (ClutterActor *self,
12789                                  const ClutterActorBox *box)
12790 {
12791   if (box != NULL)
12792     {
12793       self->priv->content_box = *box;
12794       self->priv->content_box_valid = TRUE;
12795     }
12796   else
12797     self->priv->content_box_valid = FALSE;
12798
12799   clutter_actor_queue_redraw (self);
12800
12801   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12802 }
12803
12804 static void
12805 clutter_container_iface_init (ClutterContainerIface *iface)
12806 {
12807   /* we don't override anything, as ClutterContainer already has a default
12808    * implementation that we can use, and which calls into our own API.
12809    */
12810 }
12811
12812 typedef enum
12813 {
12814   PARSE_X,
12815   PARSE_Y,
12816   PARSE_WIDTH,
12817   PARSE_HEIGHT,
12818   PARSE_ANCHOR_X,
12819   PARSE_ANCHOR_Y
12820 } ParseDimension;
12821
12822 static gfloat
12823 parse_units (ClutterActor   *self,
12824              ParseDimension  dimension,
12825              JsonNode       *node)
12826 {
12827   GValue value = G_VALUE_INIT;
12828   gfloat retval = 0;
12829
12830   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12831     return 0;
12832
12833   json_node_get_value (node, &value);
12834
12835   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12836     {
12837       retval = (gfloat) g_value_get_int64 (&value);
12838     }
12839   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12840     {
12841       retval = g_value_get_double (&value);
12842     }
12843   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12844     {
12845       ClutterUnits units;
12846       gboolean res;
12847
12848       res = clutter_units_from_string (&units, g_value_get_string (&value));
12849       if (res)
12850         retval = clutter_units_to_pixels (&units);
12851       else
12852         {
12853           g_warning ("Invalid value '%s': integers, strings or floating point "
12854                      "values can be used for the x, y, width and height "
12855                      "properties. Valid modifiers for strings are 'px', 'mm', "
12856                      "'pt' and 'em'.",
12857                      g_value_get_string (&value));
12858           retval = 0;
12859         }
12860     }
12861   else
12862     {
12863       g_warning ("Invalid value of type '%s': integers, strings of floating "
12864                  "point values can be used for the x, y, width, height "
12865                  "anchor-x and anchor-y properties.",
12866                  g_type_name (G_VALUE_TYPE (&value)));
12867     }
12868
12869   g_value_unset (&value);
12870
12871   return retval;
12872 }
12873
12874 typedef struct {
12875   ClutterRotateAxis axis;
12876
12877   gdouble angle;
12878
12879   gfloat center_x;
12880   gfloat center_y;
12881   gfloat center_z;
12882 } RotationInfo;
12883
12884 static inline gboolean
12885 parse_rotation_array (ClutterActor *actor,
12886                       JsonArray    *array,
12887                       RotationInfo *info)
12888 {
12889   JsonNode *element;
12890
12891   if (json_array_get_length (array) != 2)
12892     return FALSE;
12893
12894   /* angle */
12895   element = json_array_get_element (array, 0);
12896   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12897     info->angle = json_node_get_double (element);
12898   else
12899     return FALSE;
12900
12901   /* center */
12902   element = json_array_get_element (array, 1);
12903   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12904     {
12905       JsonArray *center = json_node_get_array (element);
12906
12907       if (json_array_get_length (center) != 2)
12908         return FALSE;
12909
12910       switch (info->axis)
12911         {
12912         case CLUTTER_X_AXIS:
12913           info->center_y = parse_units (actor, PARSE_Y,
12914                                         json_array_get_element (center, 0));
12915           info->center_z = parse_units (actor, PARSE_Y,
12916                                         json_array_get_element (center, 1));
12917           return TRUE;
12918
12919         case CLUTTER_Y_AXIS:
12920           info->center_x = parse_units (actor, PARSE_X,
12921                                         json_array_get_element (center, 0));
12922           info->center_z = parse_units (actor, PARSE_X,
12923                                         json_array_get_element (center, 1));
12924           return TRUE;
12925
12926         case CLUTTER_Z_AXIS:
12927           info->center_x = parse_units (actor, PARSE_X,
12928                                         json_array_get_element (center, 0));
12929           info->center_y = parse_units (actor, PARSE_Y,
12930                                         json_array_get_element (center, 1));
12931           return TRUE;
12932         }
12933     }
12934
12935   return FALSE;
12936 }
12937
12938 static gboolean
12939 parse_rotation (ClutterActor *actor,
12940                 JsonNode     *node,
12941                 RotationInfo *info)
12942 {
12943   JsonArray *array;
12944   guint len, i;
12945   gboolean retval = FALSE;
12946
12947   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12948     {
12949       g_warning ("Invalid node of type '%s' found, expecting an array",
12950                  json_node_type_name (node));
12951       return FALSE;
12952     }
12953
12954   array = json_node_get_array (node);
12955   len = json_array_get_length (array);
12956
12957   for (i = 0; i < len; i++)
12958     {
12959       JsonNode *element = json_array_get_element (array, i);
12960       JsonObject *object;
12961       JsonNode *member;
12962
12963       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12964         {
12965           g_warning ("Invalid node of type '%s' found, expecting an object",
12966                      json_node_type_name (element));
12967           return FALSE;
12968         }
12969
12970       object = json_node_get_object (element);
12971
12972       if (json_object_has_member (object, "x-axis"))
12973         {
12974           member = json_object_get_member (object, "x-axis");
12975
12976           info->axis = CLUTTER_X_AXIS;
12977
12978           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12979             {
12980               info->angle = json_node_get_double (member);
12981               retval = TRUE;
12982             }
12983           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12984             retval = parse_rotation_array (actor,
12985                                            json_node_get_array (member),
12986                                            info);
12987           else
12988             retval = FALSE;
12989         }
12990       else if (json_object_has_member (object, "y-axis"))
12991         {
12992           member = json_object_get_member (object, "y-axis");
12993
12994           info->axis = CLUTTER_Y_AXIS;
12995
12996           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12997             {
12998               info->angle = json_node_get_double (member);
12999               retval = TRUE;
13000             }
13001           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
13002             retval = parse_rotation_array (actor,
13003                                            json_node_get_array (member),
13004                                            info);
13005           else
13006             retval = FALSE;
13007         }
13008       else if (json_object_has_member (object, "z-axis"))
13009         {
13010           member = json_object_get_member (object, "z-axis");
13011
13012           info->axis = CLUTTER_Z_AXIS;
13013
13014           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
13015             {
13016               info->angle = json_node_get_double (member);
13017               retval = TRUE;
13018             }
13019           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
13020             retval = parse_rotation_array (actor,
13021                                            json_node_get_array (member),
13022                                            info);
13023           else
13024             retval = FALSE;
13025         }
13026     }
13027
13028   return retval;
13029 }
13030
13031 static GSList *
13032 parse_actor_metas (ClutterScript *script,
13033                    ClutterActor  *actor,
13034                    JsonNode      *node)
13035 {
13036   GList *elements, *l;
13037   GSList *retval = NULL;
13038
13039   if (!JSON_NODE_HOLDS_ARRAY (node))
13040     return NULL;
13041
13042   elements = json_array_get_elements (json_node_get_array (node));
13043
13044   for (l = elements; l != NULL; l = l->next)
13045     {
13046       JsonNode *element = l->data;
13047       const gchar *id_ = _clutter_script_get_id_from_node (element);
13048       GObject *meta;
13049
13050       if (id_ == NULL || *id_ == '\0')
13051         continue;
13052
13053       meta = clutter_script_get_object (script, id_);
13054       if (meta == NULL)
13055         continue;
13056
13057       retval = g_slist_prepend (retval, meta);
13058     }
13059
13060   g_list_free (elements);
13061
13062   return g_slist_reverse (retval);
13063 }
13064
13065 static GSList *
13066 parse_behaviours (ClutterScript *script,
13067                   ClutterActor  *actor,
13068                   JsonNode      *node)
13069 {
13070   GList *elements, *l;
13071   GSList *retval = NULL;
13072
13073   if (!JSON_NODE_HOLDS_ARRAY (node))
13074     return NULL;
13075
13076   elements = json_array_get_elements (json_node_get_array (node));
13077
13078   for (l = elements; l != NULL; l = l->next)
13079     {
13080       JsonNode *element = l->data;
13081       const gchar *id_ = _clutter_script_get_id_from_node (element);
13082       GObject *behaviour;
13083
13084       if (id_ == NULL || *id_ == '\0')
13085         continue;
13086
13087       behaviour = clutter_script_get_object (script, id_);
13088       if (behaviour == NULL)
13089         continue;
13090
13091       retval = g_slist_prepend (retval, behaviour);
13092     }
13093
13094   g_list_free (elements);
13095
13096   return g_slist_reverse (retval);
13097 }
13098
13099 static ClutterMargin *
13100 parse_margin (ClutterActor *self,
13101               JsonNode     *node)
13102 {
13103   ClutterMargin *margin;
13104   JsonArray *array;
13105
13106   if (!JSON_NODE_HOLDS_ARRAY (node))
13107     {
13108       g_warning ("The margin property must be an array of 1 to 4 elements");
13109       return NULL;
13110     }
13111
13112   margin = clutter_margin_new ();
13113   array = json_node_get_array (node);
13114   switch (json_array_get_length (array))
13115     {
13116     case 1:
13117       margin->top = margin->right = margin->bottom = margin->left =
13118         parse_units (self, 0, json_array_get_element (array, 0));
13119       break;
13120
13121     case 2:
13122       margin->top = margin->bottom =
13123         parse_units (self, 0, json_array_get_element (array, 0));
13124       margin->right = margin->left =
13125         parse_units (self, 0, json_array_get_element (array, 1));
13126       break;
13127
13128     case 3:
13129       margin->top =
13130         parse_units (self, 0, json_array_get_element (array, 0));
13131       margin->right = margin->left =
13132         parse_units (self, 0, json_array_get_element (array, 1));
13133       margin->bottom =
13134         parse_units (self, 0, json_array_get_element (array, 2));
13135       break;
13136
13137     case 4:
13138       margin->top =
13139         parse_units (self, 0, json_array_get_element (array, 0));
13140       margin->right =
13141         parse_units (self, 0, json_array_get_element (array, 1));
13142       margin->bottom =
13143         parse_units (self, 0, json_array_get_element (array, 2));
13144       margin->left =
13145         parse_units (self, 0, json_array_get_element (array, 3));
13146       break;
13147
13148     default:
13149       g_warning ("The margin property must be an array of 1 to 4 elements");
13150       clutter_margin_free (margin);
13151       return NULL;
13152     }
13153   return margin;
13154 }
13155
13156 static gboolean
13157 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
13158                                  ClutterScript     *script,
13159                                  GValue            *value,
13160                                  const gchar       *name,
13161                                  JsonNode          *node)
13162 {
13163   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13164   gboolean retval = FALSE;
13165
13166   if ((name[0] == 'x' && name[1] == '\0') ||
13167       (name[0] == 'y' && name[1] == '\0') ||
13168       (strcmp (name, "width") == 0) ||
13169       (strcmp (name, "height") == 0) ||
13170       (strcmp (name, "anchor_x") == 0) ||
13171       (strcmp (name, "anchor_y") == 0))
13172     {
13173       ParseDimension dimension;
13174       gfloat units;
13175
13176       if (name[0] == 'x')
13177         dimension = PARSE_X;
13178       else if (name[0] == 'y')
13179         dimension = PARSE_Y;
13180       else if (name[0] == 'w')
13181         dimension = PARSE_WIDTH;
13182       else if (name[0] == 'h')
13183         dimension = PARSE_HEIGHT;
13184       else if (name[0] == 'a' && name[7] == 'x')
13185         dimension = PARSE_ANCHOR_X;
13186       else if (name[0] == 'a' && name[7] == 'y')
13187         dimension = PARSE_ANCHOR_Y;
13188       else
13189         return FALSE;
13190
13191       units = parse_units (actor, dimension, node);
13192
13193       /* convert back to pixels: all properties are pixel-based */
13194       g_value_init (value, G_TYPE_FLOAT);
13195       g_value_set_float (value, units);
13196
13197       retval = TRUE;
13198     }
13199   else if (strcmp (name, "rotation") == 0)
13200     {
13201       RotationInfo *info;
13202
13203       info = g_slice_new0 (RotationInfo);
13204       retval = parse_rotation (actor, node, info);
13205
13206       if (retval)
13207         {
13208           g_value_init (value, G_TYPE_POINTER);
13209           g_value_set_pointer (value, info);
13210         }
13211       else
13212         g_slice_free (RotationInfo, info);
13213     }
13214   else if (strcmp (name, "behaviours") == 0)
13215     {
13216       GSList *l;
13217
13218 #ifdef CLUTTER_ENABLE_DEBUG
13219       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
13220         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
13221                                      "and it should not be used in newly "
13222                                      "written ClutterScript definitions.");
13223 #endif
13224
13225       l = parse_behaviours (script, actor, node);
13226
13227       g_value_init (value, G_TYPE_POINTER);
13228       g_value_set_pointer (value, l);
13229
13230       retval = TRUE;
13231     }
13232   else if (strcmp (name, "actions") == 0 ||
13233            strcmp (name, "constraints") == 0 ||
13234            strcmp (name, "effects") == 0)
13235     {
13236       GSList *l;
13237
13238       l = parse_actor_metas (script, actor, node);
13239
13240       g_value_init (value, G_TYPE_POINTER);
13241       g_value_set_pointer (value, l);
13242
13243       retval = TRUE;
13244     }
13245   else if (strcmp (name, "margin") == 0)
13246     {
13247       ClutterMargin *margin = parse_margin (actor, node);
13248
13249       if (margin)
13250         {
13251           g_value_init (value, CLUTTER_TYPE_MARGIN);
13252           g_value_set_boxed (value, margin);
13253           retval = TRUE;
13254         }
13255     }
13256
13257   return retval;
13258 }
13259
13260 static void
13261 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
13262                                    ClutterScript     *script,
13263                                    const gchar       *name,
13264                                    const GValue      *value)
13265 {
13266   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
13267
13268 #ifdef CLUTTER_ENABLE_DEBUG
13269   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
13270     {
13271       gchar *tmp = g_strdup_value_contents (value);
13272
13273       CLUTTER_NOTE (SCRIPT,
13274                     "in ClutterActor::set_custom_property('%s') = %s",
13275                     name,
13276                     tmp);
13277
13278       g_free (tmp);
13279     }
13280 #endif /* CLUTTER_ENABLE_DEBUG */
13281
13282   if (strcmp (name, "rotation") == 0)
13283     {
13284       RotationInfo *info;
13285
13286       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13287         return;
13288
13289       info = g_value_get_pointer (value);
13290
13291       clutter_actor_set_rotation (actor,
13292                                   info->axis, info->angle,
13293                                   info->center_x,
13294                                   info->center_y,
13295                                   info->center_z);
13296
13297       g_slice_free (RotationInfo, info);
13298
13299       return;
13300     }
13301
13302   if (strcmp (name, "behaviours") == 0)
13303     {
13304       GSList *behaviours, *l;
13305
13306       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13307         return;
13308
13309       behaviours = g_value_get_pointer (value);
13310       for (l = behaviours; l != NULL; l = l->next)
13311         {
13312           ClutterBehaviour *behaviour = l->data;
13313
13314           clutter_behaviour_apply (behaviour, actor);
13315         }
13316
13317       g_slist_free (behaviours);
13318
13319       return;
13320     }
13321
13322   if (strcmp (name, "actions") == 0 ||
13323       strcmp (name, "constraints") == 0 ||
13324       strcmp (name, "effects") == 0)
13325     {
13326       GSList *metas, *l;
13327
13328       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13329         return;
13330
13331       metas = g_value_get_pointer (value);
13332       for (l = metas; l != NULL; l = l->next)
13333         {
13334           if (name[0] == 'a')
13335             clutter_actor_add_action (actor, l->data);
13336
13337           if (name[0] == 'c')
13338             clutter_actor_add_constraint (actor, l->data);
13339
13340           if (name[0] == 'e')
13341             clutter_actor_add_effect (actor, l->data);
13342         }
13343
13344       g_slist_free (metas);
13345
13346       return;
13347     }
13348   if (strcmp (name, "margin") == 0)
13349     {
13350       clutter_actor_set_margin (actor, g_value_get_boxed (value));
13351       return;
13352     }
13353
13354   g_object_set_property (G_OBJECT (scriptable), name, value);
13355 }
13356
13357 static void
13358 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13359 {
13360   iface->parse_custom_node = clutter_actor_parse_custom_node;
13361   iface->set_custom_property = clutter_actor_set_custom_property;
13362 }
13363
13364 static ClutterActorMeta *
13365 get_meta_from_animation_property (ClutterActor  *actor,
13366                                   const gchar   *name,
13367                                   gchar        **name_p)
13368 {
13369   ClutterActorPrivate *priv = actor->priv;
13370   ClutterActorMeta *meta = NULL;
13371   gchar **tokens;
13372
13373   /* if this is not a special property, fall through */
13374   if (name[0] != '@')
13375     return NULL;
13376
13377   /* detect the properties named using the following spec:
13378    *
13379    *   @<section>.<meta-name>.<property-name>
13380    *
13381    * where <section> can be one of the following:
13382    *
13383    *   - actions
13384    *   - constraints
13385    *   - effects
13386    *
13387    * and <meta-name> is the name set on a specific ActorMeta
13388    */
13389
13390   tokens = g_strsplit (name + 1, ".", -1);
13391   if (tokens == NULL || g_strv_length (tokens) != 3)
13392     {
13393       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13394                     name + 1);
13395       g_strfreev (tokens);
13396       return NULL;
13397     }
13398
13399   if (strcmp (tokens[0], "actions") == 0)
13400     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13401
13402   if (strcmp (tokens[0], "constraints") == 0)
13403     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13404
13405   if (strcmp (tokens[0], "effects") == 0)
13406     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13407
13408   if (name_p != NULL)
13409     *name_p = g_strdup (tokens[2]);
13410
13411   CLUTTER_NOTE (ANIMATION,
13412                 "Looking for property '%s' of object '%s' in section '%s'",
13413                 tokens[2],
13414                 tokens[1],
13415                 tokens[0]);
13416
13417   g_strfreev (tokens);
13418
13419   return meta;
13420 }
13421
13422 static GParamSpec *
13423 clutter_actor_find_property (ClutterAnimatable *animatable,
13424                              const gchar       *property_name)
13425 {
13426   ClutterActorMeta *meta = NULL;
13427   GObjectClass *klass = NULL;
13428   GParamSpec *pspec = NULL;
13429   gchar *p_name = NULL;
13430
13431   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13432                                            property_name,
13433                                            &p_name);
13434
13435   if (meta != NULL)
13436     {
13437       klass = G_OBJECT_GET_CLASS (meta);
13438
13439       pspec = g_object_class_find_property (klass, p_name);
13440     }
13441   else
13442     {
13443       klass = G_OBJECT_GET_CLASS (animatable);
13444
13445       pspec = g_object_class_find_property (klass, property_name);
13446     }
13447
13448   g_free (p_name);
13449
13450   return pspec;
13451 }
13452
13453 static void
13454 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13455                                  const gchar       *property_name,
13456                                  GValue            *initial)
13457 {
13458   ClutterActorMeta *meta = NULL;
13459   gchar *p_name = NULL;
13460
13461   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13462                                            property_name,
13463                                            &p_name);
13464
13465   if (meta != NULL)
13466     g_object_get_property (G_OBJECT (meta), p_name, initial);
13467   else
13468     g_object_get_property (G_OBJECT (animatable), property_name, initial);
13469
13470   g_free (p_name);
13471 }
13472
13473 /*
13474  * clutter_actor_set_animatable_property:
13475  * @actor: a #ClutterActor
13476  * @prop_id: the paramspec id
13477  * @value: the value to set
13478  * @pspec: the paramspec
13479  *
13480  * Sets values of animatable properties.
13481  *
13482  * This is a variant of clutter_actor_set_property() that gets called
13483  * by the #ClutterAnimatable implementation of #ClutterActor for the
13484  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13485  * #GParamSpec.
13486  *
13487  * Unlike the implementation of #GObjectClass.set_property(), this
13488  * function will not update the interval if a transition involving an
13489  * animatable property is in progress - this avoids cycles with the
13490  * transition API calling the public API.
13491  */
13492 static void
13493 clutter_actor_set_animatable_property (ClutterActor *actor,
13494                                        guint         prop_id,
13495                                        const GValue *value,
13496                                        GParamSpec   *pspec)
13497 {
13498   GObject *obj = G_OBJECT (actor);
13499
13500   g_object_freeze_notify (obj);
13501
13502   switch (prop_id)
13503     {
13504     case PROP_X:
13505       clutter_actor_set_x_internal (actor, g_value_get_float (value));
13506       break;
13507
13508     case PROP_Y:
13509       clutter_actor_set_y_internal (actor, g_value_get_float (value));
13510       break;
13511
13512     case PROP_POSITION:
13513       clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13514       break;
13515
13516     case PROP_WIDTH:
13517       clutter_actor_set_width_internal (actor, g_value_get_float (value));
13518       break;
13519
13520     case PROP_HEIGHT:
13521       clutter_actor_set_height_internal (actor, g_value_get_float (value));
13522       break;
13523
13524     case PROP_SIZE:
13525       clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13526       break;
13527
13528     case PROP_ALLOCATION:
13529       clutter_actor_allocate_internal (actor,
13530                                        g_value_get_boxed (value),
13531                                        actor->priv->allocation_flags);
13532       break;
13533
13534     case PROP_DEPTH:
13535       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13536       break;
13537
13538     case PROP_OPACITY:
13539       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13540       break;
13541
13542     case PROP_BACKGROUND_COLOR:
13543       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13544       break;
13545
13546     case PROP_SCALE_X:
13547       clutter_actor_set_scale_factor_internal (actor,
13548                                                g_value_get_double (value),
13549                                                pspec);
13550       break;
13551
13552     case PROP_SCALE_Y:
13553       clutter_actor_set_scale_factor_internal (actor,
13554                                                g_value_get_double (value),
13555                                                pspec);
13556       break;
13557
13558     case PROP_ROTATION_ANGLE_X:
13559       clutter_actor_set_rotation_angle_internal (actor,
13560                                                  CLUTTER_X_AXIS,
13561                                                  g_value_get_double (value));
13562       break;
13563
13564     case PROP_ROTATION_ANGLE_Y:
13565       clutter_actor_set_rotation_angle_internal (actor,
13566                                                  CLUTTER_Y_AXIS,
13567                                                  g_value_get_double (value));
13568       break;
13569
13570     case PROP_ROTATION_ANGLE_Z:
13571       clutter_actor_set_rotation_angle_internal (actor,
13572                                                  CLUTTER_Z_AXIS,
13573                                                  g_value_get_double (value));
13574       break;
13575
13576     case PROP_CONTENT_BOX:
13577       clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13578       break;
13579
13580     default:
13581       g_object_set_property (obj, pspec->name, value);
13582       break;
13583     }
13584
13585   g_object_thaw_notify (obj);
13586 }
13587
13588 static void
13589 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13590                                const gchar       *property_name,
13591                                const GValue      *final)
13592 {
13593   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13594   ClutterActorMeta *meta = NULL;
13595   gchar *p_name = NULL;
13596
13597   meta = get_meta_from_animation_property (actor,
13598                                            property_name,
13599                                            &p_name);
13600   if (meta != NULL)
13601     g_object_set_property (G_OBJECT (meta), p_name, final);
13602   else
13603     {
13604       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13605       GParamSpec *pspec;
13606
13607       pspec = g_object_class_find_property (obj_class, property_name);
13608
13609       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13610         {
13611           /* XXX - I'm going to the special hell for this */
13612           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13613         }
13614       else
13615         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13616     }
13617
13618   g_free (p_name);
13619 }
13620
13621 static void
13622 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13623 {
13624   iface->find_property = clutter_actor_find_property;
13625   iface->get_initial_state = clutter_actor_get_initial_state;
13626   iface->set_final_state = clutter_actor_set_final_state;
13627 }
13628
13629 /**
13630  * clutter_actor_transform_stage_point:
13631  * @self: A #ClutterActor
13632  * @x: (in): x screen coordinate of the point to unproject
13633  * @y: (in): y screen coordinate of the point to unproject
13634  * @x_out: (out): return location for the unprojected x coordinance
13635  * @y_out: (out): return location for the unprojected y coordinance
13636  *
13637  * This function translates screen coordinates (@x, @y) to
13638  * coordinates relative to the actor. For example, it can be used to translate
13639  * screen events from global screen coordinates into actor-local coordinates.
13640  *
13641  * The conversion can fail, notably if the transform stack results in the
13642  * actor being projected on the screen as a mere line.
13643  *
13644  * The conversion should not be expected to be pixel-perfect due to the
13645  * nature of the operation. In general the error grows when the skewing
13646  * of the actor rectangle on screen increases.
13647  *
13648  * <note><para>This function can be computationally intensive.</para></note>
13649  *
13650  * <note><para>This function only works when the allocation is up-to-date,
13651  * i.e. inside of paint().</para></note>
13652  *
13653  * Return value: %TRUE if conversion was successful.
13654  *
13655  * Since: 0.6
13656  */
13657 gboolean
13658 clutter_actor_transform_stage_point (ClutterActor *self,
13659                                      gfloat        x,
13660                                      gfloat        y,
13661                                      gfloat       *x_out,
13662                                      gfloat       *y_out)
13663 {
13664   ClutterVertex v[4];
13665   float ST[3][3];
13666   float RQ[3][3];
13667   int du, dv, xi, yi;
13668   float px, py;
13669   float xf, yf, wf, det;
13670   ClutterActorPrivate *priv;
13671
13672   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13673
13674   priv = self->priv;
13675
13676   /* This implementation is based on the quad -> quad projection algorithm
13677    * described by Paul Heckbert in:
13678    *
13679    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13680    *
13681    * and the sample implementation at:
13682    *
13683    *   http://www.cs.cmu.edu/~ph/src/texfund/
13684    *
13685    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13686    * quad to rectangle only, which significantly simplifies things; the
13687    * function calls have been unrolled, and most of the math is done in fixed
13688    * point.
13689    */
13690
13691   clutter_actor_get_abs_allocation_vertices (self, v);
13692
13693   /* Keeping these as ints simplifies the multiplication (no significant
13694    * loss of precision here).
13695    */
13696   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13697   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13698
13699   if (!du || !dv)
13700     return FALSE;
13701
13702 #define UX2FP(x)        (x)
13703 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13704
13705   /* First, find mapping from unit uv square to xy quadrilateral; this
13706    * equivalent to the pmap_square_quad() functions in the sample
13707    * implementation, which we can simplify, since our target is always
13708    * a rectangle.
13709    */
13710   px = v[0].x - v[1].x + v[3].x - v[2].x;
13711   py = v[0].y - v[1].y + v[3].y - v[2].y;
13712
13713   if (!px && !py)
13714     {
13715       /* affine transform */
13716       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13717       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13718       RQ[2][0] = UX2FP (v[0].x);
13719       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13720       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13721       RQ[2][1] = UX2FP (v[0].y);
13722       RQ[0][2] = 0;
13723       RQ[1][2] = 0;
13724       RQ[2][2] = 1.0;
13725     }
13726   else
13727     {
13728       /* projective transform */
13729       double dx1, dx2, dy1, dy2, del;
13730
13731       dx1 = UX2FP (v[1].x - v[3].x);
13732       dx2 = UX2FP (v[2].x - v[3].x);
13733       dy1 = UX2FP (v[1].y - v[3].y);
13734       dy2 = UX2FP (v[2].y - v[3].y);
13735
13736       del = DET2FP (dx1, dx2, dy1, dy2);
13737       if (!del)
13738         return FALSE;
13739
13740       /*
13741        * The division here needs to be done in floating point for
13742        * precisions reasons.
13743        */
13744       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13745       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13746       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13747       RQ[2][2] = 1.0;
13748       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13749       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13750       RQ[2][0] = UX2FP (v[0].x);
13751       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13752       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13753       RQ[2][1] = UX2FP (v[0].y);
13754     }
13755
13756   /*
13757    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13758    * square. Since our rectangle is based at 0,0 we only need to scale.
13759    */
13760   RQ[0][0] /= du;
13761   RQ[1][0] /= dv;
13762   RQ[0][1] /= du;
13763   RQ[1][1] /= dv;
13764   RQ[0][2] /= du;
13765   RQ[1][2] /= dv;
13766
13767   /*
13768    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13769    * inverse of that.
13770    */
13771   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13772   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13773   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13774   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13775   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13776   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13777   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13778   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13779   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13780
13781   /*
13782    * Check the resulting matrix is OK.
13783    */
13784   det = (RQ[0][0] * ST[0][0])
13785       + (RQ[0][1] * ST[0][1])
13786       + (RQ[0][2] * ST[0][2]);
13787   if (!det)
13788     return FALSE;
13789
13790   /*
13791    * Now transform our point with the ST matrix; the notional w
13792    * coordinate is 1, hence the last part is simply added.
13793    */
13794   xi = (int) x;
13795   yi = (int) y;
13796
13797   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13798   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13799   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13800
13801   if (x_out)
13802     *x_out = xf / wf;
13803
13804   if (y_out)
13805     *y_out = yf / wf;
13806
13807 #undef UX2FP
13808 #undef DET2FP
13809
13810   return TRUE;
13811 }
13812
13813 /**
13814  * clutter_actor_is_rotated:
13815  * @self: a #ClutterActor
13816  *
13817  * Checks whether any rotation is applied to the actor.
13818  *
13819  * Return value: %TRUE if the actor is rotated.
13820  *
13821  * Since: 0.6
13822  */
13823 gboolean
13824 clutter_actor_is_rotated (ClutterActor *self)
13825 {
13826   const ClutterTransformInfo *info;
13827
13828   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13829
13830   info = _clutter_actor_get_transform_info_or_defaults (self);
13831
13832   if (info->rx_angle || info->ry_angle || info->rz_angle)
13833     return TRUE;
13834
13835   return FALSE;
13836 }
13837
13838 /**
13839  * clutter_actor_is_scaled:
13840  * @self: a #ClutterActor
13841  *
13842  * Checks whether the actor is scaled in either dimension.
13843  *
13844  * Return value: %TRUE if the actor is scaled.
13845  *
13846  * Since: 0.6
13847  */
13848 gboolean
13849 clutter_actor_is_scaled (ClutterActor *self)
13850 {
13851   const ClutterTransformInfo *info;
13852
13853   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13854
13855   info = _clutter_actor_get_transform_info_or_defaults (self);
13856
13857   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13858     return TRUE;
13859
13860   return FALSE;
13861 }
13862
13863 ClutterActor *
13864 _clutter_actor_get_stage_internal (ClutterActor *actor)
13865 {
13866   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13867     actor = actor->priv->parent;
13868
13869   return actor;
13870 }
13871
13872 /**
13873  * clutter_actor_get_stage:
13874  * @actor: a #ClutterActor
13875  *
13876  * Retrieves the #ClutterStage where @actor is contained.
13877  *
13878  * Return value: (transfer none) (type Clutter.Stage): the stage
13879  *   containing the actor, or %NULL
13880  *
13881  * Since: 0.8
13882  */
13883 ClutterActor *
13884 clutter_actor_get_stage (ClutterActor *actor)
13885 {
13886   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13887
13888   return _clutter_actor_get_stage_internal (actor);
13889 }
13890
13891 /**
13892  * clutter_actor_allocate_available_size:
13893  * @self: a #ClutterActor
13894  * @x: the actor's X coordinate
13895  * @y: the actor's Y coordinate
13896  * @available_width: the maximum available width, or -1 to use the
13897  *   actor's natural width
13898  * @available_height: the maximum available height, or -1 to use the
13899  *   actor's natural height
13900  * @flags: flags controlling the allocation
13901  *
13902  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13903  * preferred size, but limiting it to the maximum available width
13904  * and height provided.
13905  *
13906  * This function will do the right thing when dealing with the
13907  * actor's request mode.
13908  *
13909  * The implementation of this function is equivalent to:
13910  *
13911  * |[
13912  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13913  *     {
13914  *       clutter_actor_get_preferred_width (self, available_height,
13915  *                                          &amp;min_width,
13916  *                                          &amp;natural_width);
13917  *       width = CLAMP (natural_width, min_width, available_width);
13918  *
13919  *       clutter_actor_get_preferred_height (self, width,
13920  *                                           &amp;min_height,
13921  *                                           &amp;natural_height);
13922  *       height = CLAMP (natural_height, min_height, available_height);
13923  *     }
13924  *   else
13925  *     {
13926  *       clutter_actor_get_preferred_height (self, available_width,
13927  *                                           &amp;min_height,
13928  *                                           &amp;natural_height);
13929  *       height = CLAMP (natural_height, min_height, available_height);
13930  *
13931  *       clutter_actor_get_preferred_width (self, height,
13932  *                                          &amp;min_width,
13933  *                                          &amp;natural_width);
13934  *       width = CLAMP (natural_width, min_width, available_width);
13935  *     }
13936  *
13937  *   box.x1 = x; box.y1 = y;
13938  *   box.x2 = box.x1 + available_width;
13939  *   box.y2 = box.y1 + available_height;
13940  *   clutter_actor_allocate (self, &amp;box, flags);
13941  * ]|
13942  *
13943  * This function can be used by fluid layout managers to allocate
13944  * an actor's preferred size without making it bigger than the area
13945  * available for the container.
13946  *
13947  * Since: 1.0
13948  */
13949 void
13950 clutter_actor_allocate_available_size (ClutterActor           *self,
13951                                        gfloat                  x,
13952                                        gfloat                  y,
13953                                        gfloat                  available_width,
13954                                        gfloat                  available_height,
13955                                        ClutterAllocationFlags  flags)
13956 {
13957   ClutterActorPrivate *priv;
13958   gfloat width, height;
13959   gfloat min_width, min_height;
13960   gfloat natural_width, natural_height;
13961   ClutterActorBox box;
13962
13963   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13964
13965   priv = self->priv;
13966
13967   width = height = 0.0;
13968
13969   switch (priv->request_mode)
13970     {
13971     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13972       clutter_actor_get_preferred_width (self, available_height,
13973                                          &min_width,
13974                                          &natural_width);
13975       width  = CLAMP (natural_width, min_width, available_width);
13976
13977       clutter_actor_get_preferred_height (self, width,
13978                                           &min_height,
13979                                           &natural_height);
13980       height = CLAMP (natural_height, min_height, available_height);
13981       break;
13982
13983     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13984       clutter_actor_get_preferred_height (self, available_width,
13985                                           &min_height,
13986                                           &natural_height);
13987       height = CLAMP (natural_height, min_height, available_height);
13988
13989       clutter_actor_get_preferred_width (self, height,
13990                                          &min_width,
13991                                          &natural_width);
13992       width  = CLAMP (natural_width, min_width, available_width);
13993       break;
13994     }
13995
13996
13997   box.x1 = x;
13998   box.y1 = y;
13999   box.x2 = box.x1 + width;
14000   box.y2 = box.y1 + height;
14001   clutter_actor_allocate (self, &box, flags);
14002 }
14003
14004 /**
14005  * clutter_actor_allocate_preferred_size:
14006  * @self: a #ClutterActor
14007  * @flags: flags controlling the allocation
14008  *
14009  * Allocates the natural size of @self.
14010  *
14011  * This function is a utility call for #ClutterActor implementations
14012  * that allocates the actor's preferred natural size. It can be used
14013  * by fixed layout managers (like #ClutterGroup or so called
14014  * 'composite actors') inside the ClutterActor::allocate
14015  * implementation to give each child exactly how much space it
14016  * requires.
14017  *
14018  * This function is not meant to be used by applications. It is also
14019  * not meant to be used outside the implementation of the
14020  * ClutterActor::allocate virtual function.
14021  *
14022  * Since: 0.8
14023  */
14024 void
14025 clutter_actor_allocate_preferred_size (ClutterActor           *self,
14026                                        ClutterAllocationFlags  flags)
14027 {
14028   gfloat actor_x, actor_y;
14029   gfloat natural_width, natural_height;
14030   ClutterActorBox actor_box;
14031
14032   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14033
14034   actor_x = clutter_actor_get_x (self);
14035   actor_y = clutter_actor_get_y (self);
14036
14037   clutter_actor_get_preferred_size (self,
14038                                     NULL, NULL,
14039                                     &natural_width,
14040                                     &natural_height);
14041
14042   actor_box.x1 = actor_x;
14043   actor_box.y1 = actor_y;
14044   actor_box.x2 = actor_box.x1 + natural_width;
14045   actor_box.y2 = actor_box.y1 + natural_height;
14046
14047   clutter_actor_allocate (self, &actor_box, flags);
14048 }
14049
14050 /**
14051  * clutter_actor_allocate_align_fill:
14052  * @self: a #ClutterActor
14053  * @box: a #ClutterActorBox, containing the available width and height
14054  * @x_align: the horizontal alignment, between 0 and 1
14055  * @y_align: the vertical alignment, between 0 and 1
14056  * @x_fill: whether the actor should fill horizontally
14057  * @y_fill: whether the actor should fill vertically
14058  * @flags: allocation flags to be passed to clutter_actor_allocate()
14059  *
14060  * Allocates @self by taking into consideration the available allocation
14061  * area; an alignment factor on either axis; and whether the actor should
14062  * fill the allocation on either axis.
14063  *
14064  * The @box should contain the available allocation width and height;
14065  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
14066  * allocation will be offset by their value.
14067  *
14068  * This function takes into consideration the geometry request specified by
14069  * the #ClutterActor:request-mode property, and the text direction.
14070  *
14071  * This function is useful for fluid layout managers, like #ClutterBinLayout
14072  * or #ClutterTableLayout
14073  *
14074  * Since: 1.4
14075  */
14076 void
14077 clutter_actor_allocate_align_fill (ClutterActor           *self,
14078                                    const ClutterActorBox  *box,
14079                                    gdouble                 x_align,
14080                                    gdouble                 y_align,
14081                                    gboolean                x_fill,
14082                                    gboolean                y_fill,
14083                                    ClutterAllocationFlags  flags)
14084 {
14085   ClutterActorPrivate *priv;
14086   ClutterActorBox allocation = { 0, };
14087   gfloat x_offset, y_offset;
14088   gfloat available_width, available_height;
14089   gfloat child_width, child_height;
14090
14091   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14092   g_return_if_fail (box != NULL);
14093   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
14094   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
14095
14096   priv = self->priv;
14097
14098   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
14099   clutter_actor_box_get_size (box, &available_width, &available_height);
14100
14101   if (available_width < 0)
14102     available_width = 0;
14103
14104   if (available_height < 0)
14105     available_height = 0;
14106
14107   if (x_fill)
14108     {
14109       allocation.x1 = x_offset;
14110       allocation.x2 = allocation.x1 + available_width;
14111     }
14112
14113   if (y_fill)
14114     {
14115       allocation.y1 = y_offset;
14116       allocation.y2 = allocation.y1 + available_height;
14117     }
14118
14119   /* if we are filling horizontally and vertically then we're done */
14120   if (x_fill && y_fill)
14121     goto out;
14122
14123   child_width = child_height = 0.0f;
14124
14125   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
14126     {
14127       gfloat min_width, natural_width;
14128       gfloat min_height, natural_height;
14129
14130       clutter_actor_get_preferred_width (self, available_height,
14131                                          &min_width,
14132                                          &natural_width);
14133
14134       child_width = CLAMP (natural_width, min_width, available_width);
14135
14136       if (!y_fill)
14137         {
14138           clutter_actor_get_preferred_height (self, child_width,
14139                                               &min_height,
14140                                               &natural_height);
14141
14142           child_height = CLAMP (natural_height, min_height, available_height);
14143         }
14144     }
14145   else
14146     {
14147       gfloat min_width, natural_width;
14148       gfloat min_height, natural_height;
14149
14150       clutter_actor_get_preferred_height (self, available_width,
14151                                           &min_height,
14152                                           &natural_height);
14153
14154       child_height = CLAMP (natural_height, min_height, available_height);
14155
14156       if (!x_fill)
14157         {
14158           clutter_actor_get_preferred_width (self, child_height,
14159                                              &min_width,
14160                                              &natural_width);
14161
14162           child_width = CLAMP (natural_width, min_width, available_width);
14163         }
14164     }
14165
14166   /* invert the horizontal alignment for RTL languages */
14167   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
14168     x_align = 1.0 - x_align;
14169
14170   if (!x_fill)
14171     {
14172       allocation.x1 = x_offset
14173                     + ((available_width - child_width) * x_align);
14174       allocation.x2 = allocation.x1 + child_width;
14175     }
14176
14177   if (!y_fill)
14178     {
14179       allocation.y1 = y_offset
14180                     + ((available_height - child_height) * y_align);
14181       allocation.y2 = allocation.y1 + child_height;
14182     }
14183
14184 out:
14185   clutter_actor_box_clamp_to_pixel (&allocation);
14186   clutter_actor_allocate (self, &allocation, flags);
14187 }
14188
14189 /**
14190  * clutter_actor_grab_key_focus:
14191  * @self: a #ClutterActor
14192  *
14193  * Sets the key focus of the #ClutterStage including @self
14194  * to this #ClutterActor.
14195  *
14196  * Since: 1.0
14197  */
14198 void
14199 clutter_actor_grab_key_focus (ClutterActor *self)
14200 {
14201   ClutterActor *stage;
14202
14203   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14204
14205   stage = _clutter_actor_get_stage_internal (self);
14206   if (stage != NULL)
14207     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
14208 }
14209
14210 /**
14211  * clutter_actor_get_pango_context:
14212  * @self: a #ClutterActor
14213  *
14214  * Retrieves the #PangoContext for @self. The actor's #PangoContext
14215  * is already configured using the appropriate font map, resolution
14216  * and font options.
14217  *
14218  * Unlike clutter_actor_create_pango_context(), this context is owend
14219  * by the #ClutterActor and it will be updated each time the options
14220  * stored by the #ClutterBackend change.
14221  *
14222  * You can use the returned #PangoContext to create a #PangoLayout
14223  * and render text using cogl_pango_render_layout() to reuse the
14224  * glyphs cache also used by Clutter.
14225  *
14226  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
14227  *   The returned #PangoContext is owned by the actor and should not be
14228  *   unreferenced by the application code
14229  *
14230  * Since: 1.0
14231  */
14232 PangoContext *
14233 clutter_actor_get_pango_context (ClutterActor *self)
14234 {
14235   ClutterActorPrivate *priv;
14236
14237   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14238
14239   priv = self->priv;
14240
14241   if (priv->pango_context != NULL)
14242     return priv->pango_context;
14243
14244   priv->pango_context = _clutter_context_get_pango_context ();
14245   g_object_ref (priv->pango_context);
14246
14247   return priv->pango_context;
14248 }
14249
14250 /**
14251  * clutter_actor_create_pango_context:
14252  * @self: a #ClutterActor
14253  *
14254  * Creates a #PangoContext for the given actor. The #PangoContext
14255  * is already configured using the appropriate font map, resolution
14256  * and font options.
14257  *
14258  * See also clutter_actor_get_pango_context().
14259  *
14260  * Return value: (transfer full): the newly created #PangoContext.
14261  *   Use g_object_unref() on the returned value to deallocate its
14262  *   resources
14263  *
14264  * Since: 1.0
14265  */
14266 PangoContext *
14267 clutter_actor_create_pango_context (ClutterActor *self)
14268 {
14269   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14270
14271   return _clutter_context_create_pango_context ();
14272 }
14273
14274 /**
14275  * clutter_actor_create_pango_layout:
14276  * @self: a #ClutterActor
14277  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
14278  *
14279  * Creates a new #PangoLayout from the same #PangoContext used
14280  * by the #ClutterActor. The #PangoLayout is already configured
14281  * with the font map, resolution and font options, and the
14282  * given @text.
14283  *
14284  * If you want to keep around a #PangoLayout created by this
14285  * function you will have to connect to the #ClutterBackend::font-changed
14286  * and #ClutterBackend::resolution-changed signals, and call
14287  * pango_layout_context_changed() in response to them.
14288  *
14289  * Return value: (transfer full): the newly created #PangoLayout.
14290  *   Use g_object_unref() when done
14291  *
14292  * Since: 1.0
14293  */
14294 PangoLayout *
14295 clutter_actor_create_pango_layout (ClutterActor *self,
14296                                    const gchar  *text)
14297 {
14298   PangoContext *context;
14299   PangoLayout *layout;
14300
14301   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14302
14303   context = clutter_actor_get_pango_context (self);
14304   layout = pango_layout_new (context);
14305
14306   if (text)
14307     pango_layout_set_text (layout, text, -1);
14308
14309   return layout;
14310 }
14311
14312 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14313  * ClutterOffscreenEffect.
14314  */
14315 void
14316 _clutter_actor_set_opacity_override (ClutterActor *self,
14317                                      gint          opacity)
14318 {
14319   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14320
14321   self->priv->opacity_override = opacity;
14322 }
14323
14324 gint
14325 _clutter_actor_get_opacity_override (ClutterActor *self)
14326 {
14327   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14328
14329   return self->priv->opacity_override;
14330 }
14331
14332 /* Allows you to disable applying the actors model view transform during
14333  * a paint. Used by ClutterClone. */
14334 void
14335 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14336                                                 gboolean      enable)
14337 {
14338   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14339
14340   self->priv->enable_model_view_transform = enable;
14341 }
14342
14343 void
14344 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14345                                           gboolean      enable)
14346 {
14347   ClutterActorPrivate *priv;
14348
14349   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14350
14351   priv = self->priv;
14352
14353   priv->enable_paint_unmapped = enable;
14354
14355   if (priv->enable_paint_unmapped)
14356     {
14357       /* Make sure that the parents of the widget are realized first;
14358        * otherwise checks in clutter_actor_update_map_state() will
14359        * fail.
14360        */
14361       clutter_actor_realize (self);
14362
14363       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14364     }
14365   else
14366     {
14367       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14368     }
14369 }
14370
14371 static void
14372 clutter_anchor_coord_get_units (ClutterActor      *self,
14373                                 const AnchorCoord *coord,
14374                                 gfloat            *x,
14375                                 gfloat            *y,
14376                                 gfloat            *z)
14377 {
14378   if (coord->is_fractional)
14379     {
14380       gfloat actor_width, actor_height;
14381
14382       clutter_actor_get_size (self, &actor_width, &actor_height);
14383
14384       if (x)
14385         *x = actor_width * coord->v.fraction.x;
14386
14387       if (y)
14388         *y = actor_height * coord->v.fraction.y;
14389
14390       if (z)
14391         *z = 0;
14392     }
14393   else
14394     {
14395       if (x)
14396         *x = coord->v.units.x;
14397
14398       if (y)
14399         *y = coord->v.units.y;
14400
14401       if (z)
14402         *z = coord->v.units.z;
14403     }
14404 }
14405
14406 static void
14407 clutter_anchor_coord_set_units (AnchorCoord *coord,
14408                                 gfloat       x,
14409                                 gfloat       y,
14410                                 gfloat       z)
14411 {
14412   coord->is_fractional = FALSE;
14413   coord->v.units.x = x;
14414   coord->v.units.y = y;
14415   coord->v.units.z = z;
14416 }
14417
14418 static ClutterGravity
14419 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14420 {
14421   if (coord->is_fractional)
14422     {
14423       if (coord->v.fraction.x == 0.0)
14424         {
14425           if (coord->v.fraction.y == 0.0)
14426             return CLUTTER_GRAVITY_NORTH_WEST;
14427           else if (coord->v.fraction.y == 0.5)
14428             return CLUTTER_GRAVITY_WEST;
14429           else if (coord->v.fraction.y == 1.0)
14430             return CLUTTER_GRAVITY_SOUTH_WEST;
14431           else
14432             return CLUTTER_GRAVITY_NONE;
14433         }
14434       else if (coord->v.fraction.x == 0.5)
14435         {
14436           if (coord->v.fraction.y == 0.0)
14437             return CLUTTER_GRAVITY_NORTH;
14438           else if (coord->v.fraction.y == 0.5)
14439             return CLUTTER_GRAVITY_CENTER;
14440           else if (coord->v.fraction.y == 1.0)
14441             return CLUTTER_GRAVITY_SOUTH;
14442           else
14443             return CLUTTER_GRAVITY_NONE;
14444         }
14445       else if (coord->v.fraction.x == 1.0)
14446         {
14447           if (coord->v.fraction.y == 0.0)
14448             return CLUTTER_GRAVITY_NORTH_EAST;
14449           else if (coord->v.fraction.y == 0.5)
14450             return CLUTTER_GRAVITY_EAST;
14451           else if (coord->v.fraction.y == 1.0)
14452             return CLUTTER_GRAVITY_SOUTH_EAST;
14453           else
14454             return CLUTTER_GRAVITY_NONE;
14455         }
14456       else
14457         return CLUTTER_GRAVITY_NONE;
14458     }
14459   else
14460     return CLUTTER_GRAVITY_NONE;
14461 }
14462
14463 static void
14464 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14465                                   ClutterGravity  gravity)
14466 {
14467   switch (gravity)
14468     {
14469     case CLUTTER_GRAVITY_NORTH:
14470       coord->v.fraction.x = 0.5;
14471       coord->v.fraction.y = 0.0;
14472       break;
14473
14474     case CLUTTER_GRAVITY_NORTH_EAST:
14475       coord->v.fraction.x = 1.0;
14476       coord->v.fraction.y = 0.0;
14477       break;
14478
14479     case CLUTTER_GRAVITY_EAST:
14480       coord->v.fraction.x = 1.0;
14481       coord->v.fraction.y = 0.5;
14482       break;
14483
14484     case CLUTTER_GRAVITY_SOUTH_EAST:
14485       coord->v.fraction.x = 1.0;
14486       coord->v.fraction.y = 1.0;
14487       break;
14488
14489     case CLUTTER_GRAVITY_SOUTH:
14490       coord->v.fraction.x = 0.5;
14491       coord->v.fraction.y = 1.0;
14492       break;
14493
14494     case CLUTTER_GRAVITY_SOUTH_WEST:
14495       coord->v.fraction.x = 0.0;
14496       coord->v.fraction.y = 1.0;
14497       break;
14498
14499     case CLUTTER_GRAVITY_WEST:
14500       coord->v.fraction.x = 0.0;
14501       coord->v.fraction.y = 0.5;
14502       break;
14503
14504     case CLUTTER_GRAVITY_NORTH_WEST:
14505       coord->v.fraction.x = 0.0;
14506       coord->v.fraction.y = 0.0;
14507       break;
14508
14509     case CLUTTER_GRAVITY_CENTER:
14510       coord->v.fraction.x = 0.5;
14511       coord->v.fraction.y = 0.5;
14512       break;
14513
14514     default:
14515       coord->v.fraction.x = 0.0;
14516       coord->v.fraction.y = 0.0;
14517       break;
14518     }
14519
14520   coord->is_fractional = TRUE;
14521 }
14522
14523 static gboolean
14524 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14525 {
14526   if (coord->is_fractional)
14527     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14528   else
14529     return (coord->v.units.x == 0.0
14530             && coord->v.units.y == 0.0
14531             && coord->v.units.z == 0.0);
14532 }
14533
14534 /**
14535  * clutter_actor_get_flags:
14536  * @self: a #ClutterActor
14537  *
14538  * Retrieves the flags set on @self
14539  *
14540  * Return value: a bitwise or of #ClutterActorFlags or 0
14541  *
14542  * Since: 1.0
14543  */
14544 ClutterActorFlags
14545 clutter_actor_get_flags (ClutterActor *self)
14546 {
14547   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14548
14549   return self->flags;
14550 }
14551
14552 /**
14553  * clutter_actor_set_flags:
14554  * @self: a #ClutterActor
14555  * @flags: the flags to set
14556  *
14557  * Sets @flags on @self
14558  *
14559  * This function will emit notifications for the changed properties
14560  *
14561  * Since: 1.0
14562  */
14563 void
14564 clutter_actor_set_flags (ClutterActor      *self,
14565                          ClutterActorFlags  flags)
14566 {
14567   ClutterActorFlags old_flags;
14568   GObject *obj;
14569   gboolean was_reactive_set, reactive_set;
14570   gboolean was_realized_set, realized_set;
14571   gboolean was_mapped_set, mapped_set;
14572   gboolean was_visible_set, visible_set;
14573
14574   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14575
14576   if (self->flags == flags)
14577     return;
14578
14579   obj = G_OBJECT (self);
14580   g_object_ref (obj);
14581   g_object_freeze_notify (obj);
14582
14583   old_flags = self->flags;
14584
14585   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14586   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14587   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14588   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14589
14590   self->flags |= flags;
14591
14592   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14593   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14594   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14595   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14596
14597   if (reactive_set != was_reactive_set)
14598     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14599
14600   if (realized_set != was_realized_set)
14601     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14602
14603   if (mapped_set != was_mapped_set)
14604     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14605
14606   if (visible_set != was_visible_set)
14607     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14608
14609   g_object_thaw_notify (obj);
14610   g_object_unref (obj);
14611 }
14612
14613 /**
14614  * clutter_actor_unset_flags:
14615  * @self: a #ClutterActor
14616  * @flags: the flags to unset
14617  *
14618  * Unsets @flags on @self
14619  *
14620  * This function will emit notifications for the changed properties
14621  *
14622  * Since: 1.0
14623  */
14624 void
14625 clutter_actor_unset_flags (ClutterActor      *self,
14626                            ClutterActorFlags  flags)
14627 {
14628   ClutterActorFlags old_flags;
14629   GObject *obj;
14630   gboolean was_reactive_set, reactive_set;
14631   gboolean was_realized_set, realized_set;
14632   gboolean was_mapped_set, mapped_set;
14633   gboolean was_visible_set, visible_set;
14634
14635   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14636
14637   obj = G_OBJECT (self);
14638   g_object_freeze_notify (obj);
14639
14640   old_flags = self->flags;
14641
14642   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14643   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14644   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14645   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14646
14647   self->flags &= ~flags;
14648
14649   if (self->flags == old_flags)
14650     return;
14651
14652   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14653   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14654   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14655   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14656
14657   if (reactive_set != was_reactive_set)
14658     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14659
14660   if (realized_set != was_realized_set)
14661     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14662
14663   if (mapped_set != was_mapped_set)
14664     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14665
14666   if (visible_set != was_visible_set)
14667     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14668
14669   g_object_thaw_notify (obj);
14670 }
14671
14672 /**
14673  * clutter_actor_get_transformation_matrix:
14674  * @self: a #ClutterActor
14675  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14676  *
14677  * Retrieves the transformations applied to @self relative to its
14678  * parent.
14679  *
14680  * Since: 1.0
14681  */
14682 void
14683 clutter_actor_get_transformation_matrix (ClutterActor *self,
14684                                          CoglMatrix   *matrix)
14685 {
14686   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14687
14688   cogl_matrix_init_identity (matrix);
14689
14690   _clutter_actor_apply_modelview_transform (self, matrix);
14691 }
14692
14693 void
14694 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14695                                    gboolean      is_in_clone_paint)
14696 {
14697   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14698   self->priv->in_clone_paint = is_in_clone_paint;
14699 }
14700
14701 /**
14702  * clutter_actor_is_in_clone_paint:
14703  * @self: a #ClutterActor
14704  *
14705  * Checks whether @self is being currently painted by a #ClutterClone
14706  *
14707  * This function is useful only inside the ::paint virtual function
14708  * implementations or within handlers for the #ClutterActor::paint
14709  * signal
14710  *
14711  * This function should not be used by applications
14712  *
14713  * Return value: %TRUE if the #ClutterActor is currently being painted
14714  *   by a #ClutterClone, and %FALSE otherwise
14715  *
14716  * Since: 1.0
14717  */
14718 gboolean
14719 clutter_actor_is_in_clone_paint (ClutterActor *self)
14720 {
14721   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14722
14723   return self->priv->in_clone_paint;
14724 }
14725
14726 static gboolean
14727 set_direction_recursive (ClutterActor *actor,
14728                          gpointer      user_data)
14729 {
14730   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14731
14732   clutter_actor_set_text_direction (actor, text_dir);
14733
14734   return TRUE;
14735 }
14736
14737 /**
14738  * clutter_actor_set_text_direction:
14739  * @self: a #ClutterActor
14740  * @text_dir: the text direction for @self
14741  *
14742  * Sets the #ClutterTextDirection for an actor
14743  *
14744  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14745  *
14746  * If @self implements #ClutterContainer then this function will recurse
14747  * inside all the children of @self (including the internal ones).
14748  *
14749  * Composite actors not implementing #ClutterContainer, or actors requiring
14750  * special handling when the text direction changes, should connect to
14751  * the #GObject::notify signal for the #ClutterActor:text-direction property
14752  *
14753  * Since: 1.2
14754  */
14755 void
14756 clutter_actor_set_text_direction (ClutterActor         *self,
14757                                   ClutterTextDirection  text_dir)
14758 {
14759   ClutterActorPrivate *priv;
14760
14761   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14762   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14763
14764   priv = self->priv;
14765
14766   if (priv->text_direction != text_dir)
14767     {
14768       priv->text_direction = text_dir;
14769
14770       /* we need to emit the notify::text-direction first, so that
14771        * the sub-classes can catch that and do specific handling of
14772        * the text direction; see clutter_text_direction_changed_cb()
14773        * inside clutter-text.c
14774        */
14775       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14776
14777       _clutter_actor_foreach_child (self, set_direction_recursive,
14778                                     GINT_TO_POINTER (text_dir));
14779
14780       clutter_actor_queue_relayout (self);
14781     }
14782 }
14783
14784 void
14785 _clutter_actor_set_has_pointer (ClutterActor *self,
14786                                 gboolean      has_pointer)
14787 {
14788   ClutterActorPrivate *priv = self->priv;
14789
14790   if (priv->has_pointer != has_pointer)
14791     {
14792       priv->has_pointer = has_pointer;
14793
14794       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14795     }
14796 }
14797
14798 /**
14799  * clutter_actor_get_text_direction:
14800  * @self: a #ClutterActor
14801  *
14802  * Retrieves the value set using clutter_actor_set_text_direction()
14803  *
14804  * If no text direction has been previously set, the default text
14805  * direction, as returned by clutter_get_default_text_direction(), will
14806  * be returned instead
14807  *
14808  * Return value: the #ClutterTextDirection for the actor
14809  *
14810  * Since: 1.2
14811  */
14812 ClutterTextDirection
14813 clutter_actor_get_text_direction (ClutterActor *self)
14814 {
14815   ClutterActorPrivate *priv;
14816
14817   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14818                         CLUTTER_TEXT_DIRECTION_LTR);
14819
14820   priv = self->priv;
14821
14822   /* if no direction has been set yet use the default */
14823   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14824     priv->text_direction = clutter_get_default_text_direction ();
14825
14826   return priv->text_direction;
14827 }
14828
14829 /**
14830  * clutter_actor_push_internal:
14831  * @self: a #ClutterActor
14832  *
14833  * Should be used by actors implementing the #ClutterContainer and with
14834  * internal children added through clutter_actor_set_parent(), for instance:
14835  *
14836  * |[
14837  *   static void
14838  *   my_actor_init (MyActor *self)
14839  *   {
14840  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14841  *
14842  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14843  *
14844  *     /&ast; calling clutter_actor_set_parent() now will result in
14845  *      &ast; the internal flag being set on a child of MyActor
14846  *      &ast;/
14847  *
14848  *     /&ast; internal child - a background texture &ast;/
14849  *     self->priv->background_tex = clutter_texture_new ();
14850  *     clutter_actor_set_parent (self->priv->background_tex,
14851  *                               CLUTTER_ACTOR (self));
14852  *
14853  *     /&ast; internal child - a label &ast;/
14854  *     self->priv->label = clutter_text_new ();
14855  *     clutter_actor_set_parent (self->priv->label,
14856  *                               CLUTTER_ACTOR (self));
14857  *
14858  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14859  *
14860  *     /&ast; calling clutter_actor_set_parent() now will not result in
14861  *      &ast; the internal flag being set on a child of MyActor
14862  *      &ast;/
14863  *   }
14864  * ]|
14865  *
14866  * This function will be used by Clutter to toggle an "internal child"
14867  * flag whenever clutter_actor_set_parent() is called; internal children
14868  * are handled differently by Clutter, specifically when destroying their
14869  * parent.
14870  *
14871  * Call clutter_actor_pop_internal() when you finished adding internal
14872  * children.
14873  *
14874  * Nested calls to clutter_actor_push_internal() are allowed, but each
14875  * one must by followed by a clutter_actor_pop_internal() call.
14876  *
14877  * Since: 1.2
14878  *
14879  * Deprecated: 1.10: All children of an actor are accessible through
14880  *   the #ClutterActor API, and #ClutterActor implements the
14881  *   #ClutterContainer interface, so this function is only useful
14882  *   for legacy containers overriding the default implementation.
14883  */
14884 void
14885 clutter_actor_push_internal (ClutterActor *self)
14886 {
14887   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14888
14889   self->priv->internal_child += 1;
14890 }
14891
14892 /**
14893  * clutter_actor_pop_internal:
14894  * @self: a #ClutterActor
14895  *
14896  * Disables the effects of clutter_actor_push_internal().
14897  *
14898  * Since: 1.2
14899  *
14900  * Deprecated: 1.10: All children of an actor are accessible through
14901  *   the #ClutterActor API. This function is only useful for legacy
14902  *   containers overriding the default implementation of the
14903  *   #ClutterContainer interface.
14904  */
14905 void
14906 clutter_actor_pop_internal (ClutterActor *self)
14907 {
14908   ClutterActorPrivate *priv;
14909
14910   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14911
14912   priv = self->priv;
14913
14914   if (priv->internal_child == 0)
14915     {
14916       g_warning ("Mismatched %s: you need to call "
14917                  "clutter_actor_push_composite() at least once before "
14918                  "calling this function", G_STRFUNC);
14919       return;
14920     }
14921
14922   priv->internal_child -= 1;
14923 }
14924
14925 /**
14926  * clutter_actor_has_pointer:
14927  * @self: a #ClutterActor
14928  *
14929  * Checks whether an actor contains the pointer of a
14930  * #ClutterInputDevice
14931  *
14932  * Return value: %TRUE if the actor contains the pointer, and
14933  *   %FALSE otherwise
14934  *
14935  * Since: 1.2
14936  */
14937 gboolean
14938 clutter_actor_has_pointer (ClutterActor *self)
14939 {
14940   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14941
14942   return self->priv->has_pointer;
14943 }
14944
14945 /* XXX: This is a workaround for not being able to break the ABI of
14946  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14947  * clutter_actor_queue_clipped_redraw() for details.
14948  */
14949 ClutterPaintVolume *
14950 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14951 {
14952   return g_object_get_data (G_OBJECT (self),
14953                             "-clutter-actor-queue-redraw-clip");
14954 }
14955
14956 void
14957 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14958                                       ClutterPaintVolume *clip)
14959 {
14960   g_object_set_data (G_OBJECT (self),
14961                      "-clutter-actor-queue-redraw-clip",
14962                      clip);
14963 }
14964
14965 /**
14966  * clutter_actor_has_allocation:
14967  * @self: a #ClutterActor
14968  *
14969  * Checks if the actor has an up-to-date allocation assigned to
14970  * it. This means that the actor should have an allocation: it's
14971  * visible and has a parent. It also means that there is no
14972  * outstanding relayout request in progress for the actor or its
14973  * children (There might be other outstanding layout requests in
14974  * progress that will cause the actor to get a new allocation
14975  * when the stage is laid out, however).
14976  *
14977  * If this function returns %FALSE, then the actor will normally
14978  * be allocated before it is next drawn on the screen.
14979  *
14980  * Return value: %TRUE if the actor has an up-to-date allocation
14981  *
14982  * Since: 1.4
14983  */
14984 gboolean
14985 clutter_actor_has_allocation (ClutterActor *self)
14986 {
14987   ClutterActorPrivate *priv;
14988
14989   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14990
14991   priv = self->priv;
14992
14993   return priv->parent != NULL &&
14994          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14995          !priv->needs_allocation;
14996 }
14997
14998 /**
14999  * clutter_actor_add_action:
15000  * @self: a #ClutterActor
15001  * @action: a #ClutterAction
15002  *
15003  * Adds @action to the list of actions applied to @self
15004  *
15005  * A #ClutterAction can only belong to one actor at a time
15006  *
15007  * The #ClutterActor will hold a reference on @action until either
15008  * clutter_actor_remove_action() or clutter_actor_clear_actions()
15009  * is called
15010  *
15011  * Since: 1.4
15012  */
15013 void
15014 clutter_actor_add_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     {
15026       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15027       priv->actions->actor = self;
15028     }
15029
15030   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
15031
15032   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15033 }
15034
15035 /**
15036  * clutter_actor_add_action_with_name:
15037  * @self: a #ClutterActor
15038  * @name: the name to set on the action
15039  * @action: a #ClutterAction
15040  *
15041  * A convenience function for setting the name of a #ClutterAction
15042  * while adding it to the list of actions applied to @self
15043  *
15044  * This function is the logical equivalent of:
15045  *
15046  * |[
15047  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
15048  *   clutter_actor_add_action (self, action);
15049  * ]|
15050  *
15051  * Since: 1.4
15052  */
15053 void
15054 clutter_actor_add_action_with_name (ClutterActor  *self,
15055                                     const gchar   *name,
15056                                     ClutterAction *action)
15057 {
15058   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15059   g_return_if_fail (name != NULL);
15060   g_return_if_fail (CLUTTER_IS_ACTION (action));
15061
15062   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
15063   clutter_actor_add_action (self, action);
15064 }
15065
15066 /**
15067  * clutter_actor_remove_action:
15068  * @self: a #ClutterActor
15069  * @action: a #ClutterAction
15070  *
15071  * Removes @action from the list of actions applied to @self
15072  *
15073  * The reference held by @self on the #ClutterAction will be released
15074  *
15075  * Since: 1.4
15076  */
15077 void
15078 clutter_actor_remove_action (ClutterActor  *self,
15079                              ClutterAction *action)
15080 {
15081   ClutterActorPrivate *priv;
15082
15083   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15084   g_return_if_fail (CLUTTER_IS_ACTION (action));
15085
15086   priv = self->priv;
15087
15088   if (priv->actions == NULL)
15089     return;
15090
15091   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
15092
15093   if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
15094     g_clear_object (&priv->actions);
15095
15096   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15097 }
15098
15099 /**
15100  * clutter_actor_remove_action_by_name:
15101  * @self: a #ClutterActor
15102  * @name: the name of the action to remove
15103  *
15104  * Removes the #ClutterAction with the given name from the list
15105  * of actions applied to @self
15106  *
15107  * Since: 1.4
15108  */
15109 void
15110 clutter_actor_remove_action_by_name (ClutterActor *self,
15111                                      const gchar  *name)
15112 {
15113   ClutterActorPrivate *priv;
15114   ClutterActorMeta *meta;
15115
15116   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15117   g_return_if_fail (name != NULL);
15118
15119   priv = self->priv;
15120
15121   if (priv->actions == NULL)
15122     return;
15123
15124   meta = _clutter_meta_group_get_meta (priv->actions, name);
15125   if (meta == NULL)
15126     return;
15127
15128   _clutter_meta_group_remove_meta (priv->actions, meta);
15129
15130   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
15131 }
15132
15133 /**
15134  * clutter_actor_get_actions:
15135  * @self: a #ClutterActor
15136  *
15137  * Retrieves the list of actions applied to @self
15138  *
15139  * Return value: (transfer container) (element-type Clutter.Action): a copy
15140  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
15141  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15142  *   allocated by the returned #GList
15143  *
15144  * Since: 1.4
15145  */
15146 GList *
15147 clutter_actor_get_actions (ClutterActor *self)
15148 {
15149   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15150
15151   if (self->priv->actions == NULL)
15152     return NULL;
15153
15154   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
15155 }
15156
15157 /**
15158  * clutter_actor_get_action:
15159  * @self: a #ClutterActor
15160  * @name: the name of the action to retrieve
15161  *
15162  * Retrieves the #ClutterAction with the given name in the list
15163  * of actions applied to @self
15164  *
15165  * Return value: (transfer none): a #ClutterAction for the given
15166  *   name, or %NULL. The returned #ClutterAction is owned by the
15167  *   actor and it should not be unreferenced directly
15168  *
15169  * Since: 1.4
15170  */
15171 ClutterAction *
15172 clutter_actor_get_action (ClutterActor *self,
15173                           const gchar  *name)
15174 {
15175   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15176   g_return_val_if_fail (name != NULL, NULL);
15177
15178   if (self->priv->actions == NULL)
15179     return NULL;
15180
15181   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
15182 }
15183
15184 /**
15185  * clutter_actor_clear_actions:
15186  * @self: a #ClutterActor
15187  *
15188  * Clears the list of actions applied to @self
15189  *
15190  * Since: 1.4
15191  */
15192 void
15193 clutter_actor_clear_actions (ClutterActor *self)
15194 {
15195   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15196
15197   if (self->priv->actions == NULL)
15198     return;
15199
15200   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
15201 }
15202
15203 /**
15204  * clutter_actor_add_constraint:
15205  * @self: a #ClutterActor
15206  * @constraint: a #ClutterConstraint
15207  *
15208  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
15209  * to @self
15210  *
15211  * The #ClutterActor will hold a reference on the @constraint until
15212  * either clutter_actor_remove_constraint() or
15213  * clutter_actor_clear_constraints() is called.
15214  *
15215  * Since: 1.4
15216  */
15217 void
15218 clutter_actor_add_constraint (ClutterActor      *self,
15219                               ClutterConstraint *constraint)
15220 {
15221   ClutterActorPrivate *priv;
15222
15223   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15224   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15225
15226   priv = self->priv;
15227
15228   if (priv->constraints == NULL)
15229     {
15230       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
15231       priv->constraints->actor = self;
15232     }
15233
15234   _clutter_meta_group_add_meta (priv->constraints,
15235                                 CLUTTER_ACTOR_META (constraint));
15236   clutter_actor_queue_relayout (self);
15237
15238   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15239 }
15240
15241 /**
15242  * clutter_actor_add_constraint_with_name:
15243  * @self: a #ClutterActor
15244  * @name: the name to set on the constraint
15245  * @constraint: a #ClutterConstraint
15246  *
15247  * A convenience function for setting the name of a #ClutterConstraint
15248  * while adding it to the list of constraints applied to @self
15249  *
15250  * This function is the logical equivalent of:
15251  *
15252  * |[
15253  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15254  *   clutter_actor_add_constraint (self, constraint);
15255  * ]|
15256  *
15257  * Since: 1.4
15258  */
15259 void
15260 clutter_actor_add_constraint_with_name (ClutterActor      *self,
15261                                         const gchar       *name,
15262                                         ClutterConstraint *constraint)
15263 {
15264   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15265   g_return_if_fail (name != NULL);
15266   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15267
15268   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
15269   clutter_actor_add_constraint (self, constraint);
15270 }
15271
15272 /**
15273  * clutter_actor_remove_constraint:
15274  * @self: a #ClutterActor
15275  * @constraint: a #ClutterConstraint
15276  *
15277  * Removes @constraint from the list of constraints applied to @self
15278  *
15279  * The reference held by @self on the #ClutterConstraint will be released
15280  *
15281  * Since: 1.4
15282  */
15283 void
15284 clutter_actor_remove_constraint (ClutterActor      *self,
15285                                  ClutterConstraint *constraint)
15286 {
15287   ClutterActorPrivate *priv;
15288
15289   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15290   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
15291
15292   priv = self->priv;
15293
15294   if (priv->constraints == NULL)
15295     return;
15296
15297   _clutter_meta_group_remove_meta (priv->constraints,
15298                                    CLUTTER_ACTOR_META (constraint));
15299
15300   if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
15301     g_clear_object (&priv->constraints);
15302
15303   clutter_actor_queue_relayout (self);
15304
15305   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15306 }
15307
15308 /**
15309  * clutter_actor_remove_constraint_by_name:
15310  * @self: a #ClutterActor
15311  * @name: the name of the constraint to remove
15312  *
15313  * Removes the #ClutterConstraint with the given name from the list
15314  * of constraints applied to @self
15315  *
15316  * Since: 1.4
15317  */
15318 void
15319 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15320                                          const gchar  *name)
15321 {
15322   ClutterActorPrivate *priv;
15323   ClutterActorMeta *meta;
15324
15325   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15326   g_return_if_fail (name != NULL);
15327
15328   priv = self->priv;
15329
15330   if (priv->constraints == NULL)
15331     return;
15332
15333   meta = _clutter_meta_group_get_meta (priv->constraints, name);
15334   if (meta == NULL)
15335     return;
15336
15337   _clutter_meta_group_remove_meta (priv->constraints, meta);
15338   clutter_actor_queue_relayout (self);
15339 }
15340
15341 /**
15342  * clutter_actor_get_constraints:
15343  * @self: a #ClutterActor
15344  *
15345  * Retrieves the list of constraints applied to @self
15346  *
15347  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15348  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15349  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15350  *   allocated by the returned #GList
15351  *
15352  * Since: 1.4
15353  */
15354 GList *
15355 clutter_actor_get_constraints (ClutterActor *self)
15356 {
15357   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15358
15359   if (self->priv->constraints == NULL)
15360     return NULL;
15361
15362   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15363 }
15364
15365 /**
15366  * clutter_actor_get_constraint:
15367  * @self: a #ClutterActor
15368  * @name: the name of the constraint to retrieve
15369  *
15370  * Retrieves the #ClutterConstraint with the given name in the list
15371  * of constraints applied to @self
15372  *
15373  * Return value: (transfer none): a #ClutterConstraint for the given
15374  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15375  *   actor and it should not be unreferenced directly
15376  *
15377  * Since: 1.4
15378  */
15379 ClutterConstraint *
15380 clutter_actor_get_constraint (ClutterActor *self,
15381                               const gchar  *name)
15382 {
15383   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15384   g_return_val_if_fail (name != NULL, NULL);
15385
15386   if (self->priv->constraints == NULL)
15387     return NULL;
15388
15389   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15390 }
15391
15392 /**
15393  * clutter_actor_clear_constraints:
15394  * @self: a #ClutterActor
15395  *
15396  * Clears the list of constraints applied to @self
15397  *
15398  * Since: 1.4
15399  */
15400 void
15401 clutter_actor_clear_constraints (ClutterActor *self)
15402 {
15403   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15404
15405   if (self->priv->constraints == NULL)
15406     return;
15407
15408   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15409
15410   clutter_actor_queue_relayout (self);
15411 }
15412
15413 /**
15414  * clutter_actor_set_clip_to_allocation:
15415  * @self: a #ClutterActor
15416  * @clip_set: %TRUE to apply a clip tracking the allocation
15417  *
15418  * Sets whether @self should be clipped to the same size as its
15419  * allocation
15420  *
15421  * Since: 1.4
15422  */
15423 void
15424 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15425                                       gboolean      clip_set)
15426 {
15427   ClutterActorPrivate *priv;
15428
15429   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15430
15431   clip_set = !!clip_set;
15432
15433   priv = self->priv;
15434
15435   if (priv->clip_to_allocation != clip_set)
15436     {
15437       priv->clip_to_allocation = clip_set;
15438
15439       clutter_actor_queue_redraw (self);
15440
15441       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15442     }
15443 }
15444
15445 /**
15446  * clutter_actor_get_clip_to_allocation:
15447  * @self: a #ClutterActor
15448  *
15449  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15450  *
15451  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15452  *
15453  * Since: 1.4
15454  */
15455 gboolean
15456 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15457 {
15458   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15459
15460   return self->priv->clip_to_allocation;
15461 }
15462
15463 /**
15464  * clutter_actor_add_effect:
15465  * @self: a #ClutterActor
15466  * @effect: a #ClutterEffect
15467  *
15468  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15469  *
15470  * The #ClutterActor will hold a reference on the @effect until either
15471  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15472  * called.
15473  *
15474  * Since: 1.4
15475  */
15476 void
15477 clutter_actor_add_effect (ClutterActor  *self,
15478                           ClutterEffect *effect)
15479 {
15480   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15481   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15482
15483   _clutter_actor_add_effect_internal (self, effect);
15484
15485   clutter_actor_queue_redraw (self);
15486
15487   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15488 }
15489
15490 /**
15491  * clutter_actor_add_effect_with_name:
15492  * @self: a #ClutterActor
15493  * @name: the name to set on the effect
15494  * @effect: a #ClutterEffect
15495  *
15496  * A convenience function for setting the name of a #ClutterEffect
15497  * while adding it to the list of effectss applied to @self
15498  *
15499  * This function is the logical equivalent of:
15500  *
15501  * |[
15502  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15503  *   clutter_actor_add_effect (self, effect);
15504  * ]|
15505  *
15506  * Since: 1.4
15507  */
15508 void
15509 clutter_actor_add_effect_with_name (ClutterActor  *self,
15510                                     const gchar   *name,
15511                                     ClutterEffect *effect)
15512 {
15513   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15514   g_return_if_fail (name != NULL);
15515   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15516
15517   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15518   clutter_actor_add_effect (self, effect);
15519 }
15520
15521 /**
15522  * clutter_actor_remove_effect:
15523  * @self: a #ClutterActor
15524  * @effect: a #ClutterEffect
15525  *
15526  * Removes @effect from the list of effects applied to @self
15527  *
15528  * The reference held by @self on the #ClutterEffect will be released
15529  *
15530  * Since: 1.4
15531  */
15532 void
15533 clutter_actor_remove_effect (ClutterActor  *self,
15534                              ClutterEffect *effect)
15535 {
15536   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15537   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15538
15539   _clutter_actor_remove_effect_internal (self, effect);
15540
15541   clutter_actor_queue_redraw (self);
15542
15543   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15544 }
15545
15546 /**
15547  * clutter_actor_remove_effect_by_name:
15548  * @self: a #ClutterActor
15549  * @name: the name of the effect to remove
15550  *
15551  * Removes the #ClutterEffect with the given name from the list
15552  * of effects applied to @self
15553  *
15554  * Since: 1.4
15555  */
15556 void
15557 clutter_actor_remove_effect_by_name (ClutterActor *self,
15558                                      const gchar  *name)
15559 {
15560   ClutterActorPrivate *priv;
15561   ClutterActorMeta *meta;
15562
15563   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15564   g_return_if_fail (name != NULL);
15565
15566   priv = self->priv;
15567
15568   if (priv->effects == NULL)
15569     return;
15570
15571   meta = _clutter_meta_group_get_meta (priv->effects, name);
15572   if (meta == NULL)
15573     return;
15574
15575   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15576 }
15577
15578 /**
15579  * clutter_actor_get_effects:
15580  * @self: a #ClutterActor
15581  *
15582  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15583  *
15584  * Return value: (transfer container) (element-type Clutter.Effect): a list
15585  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15586  *   list are owned by Clutter and they should not be freed. You should
15587  *   free the returned list using g_list_free() when done
15588  *
15589  * Since: 1.4
15590  */
15591 GList *
15592 clutter_actor_get_effects (ClutterActor *self)
15593 {
15594   ClutterActorPrivate *priv;
15595
15596   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15597
15598   priv = self->priv;
15599
15600   if (priv->effects == NULL)
15601     return NULL;
15602
15603   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15604 }
15605
15606 /**
15607  * clutter_actor_get_effect:
15608  * @self: a #ClutterActor
15609  * @name: the name of the effect to retrieve
15610  *
15611  * Retrieves the #ClutterEffect with the given name in the list
15612  * of effects applied to @self
15613  *
15614  * Return value: (transfer none): a #ClutterEffect for the given
15615  *   name, or %NULL. The returned #ClutterEffect is owned by the
15616  *   actor and it should not be unreferenced directly
15617  *
15618  * Since: 1.4
15619  */
15620 ClutterEffect *
15621 clutter_actor_get_effect (ClutterActor *self,
15622                           const gchar  *name)
15623 {
15624   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15625   g_return_val_if_fail (name != NULL, NULL);
15626
15627   if (self->priv->effects == NULL)
15628     return NULL;
15629
15630   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15631 }
15632
15633 /**
15634  * clutter_actor_clear_effects:
15635  * @self: a #ClutterActor
15636  *
15637  * Clears the list of effects applied to @self
15638  *
15639  * Since: 1.4
15640  */
15641 void
15642 clutter_actor_clear_effects (ClutterActor *self)
15643 {
15644   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15645
15646   if (self->priv->effects == NULL)
15647     return;
15648
15649   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15650
15651   clutter_actor_queue_redraw (self);
15652 }
15653
15654 /**
15655  * clutter_actor_has_key_focus:
15656  * @self: a #ClutterActor
15657  *
15658  * Checks whether @self is the #ClutterActor that has key focus
15659  *
15660  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15661  *
15662  * Since: 1.4
15663  */
15664 gboolean
15665 clutter_actor_has_key_focus (ClutterActor *self)
15666 {
15667   ClutterActor *stage;
15668
15669   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15670
15671   stage = _clutter_actor_get_stage_internal (self);
15672   if (stage == NULL)
15673     return FALSE;
15674
15675   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15676 }
15677
15678 static gboolean
15679 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15680                                       ClutterPaintVolume *pv)
15681 {
15682   ClutterActorPrivate *priv = self->priv;
15683
15684   /* Actors are only expected to report a valid paint volume
15685    * while they have a valid allocation. */
15686   if (G_UNLIKELY (priv->needs_allocation))
15687     {
15688       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15689                     "Actor needs allocation",
15690                     _clutter_actor_get_debug_name (self));
15691       return FALSE;
15692     }
15693
15694   /* Check if there are any handlers connected to the paint
15695    * signal. If there are then all bets are off for what the paint
15696    * volume for this actor might possibly be!
15697    *
15698    * XXX: It's expected that this is going to end up being quite a
15699    * costly check to have to do here, but we haven't come up with
15700    * another solution that can reliably catch paint signal handlers at
15701    * the right time to either avoid artefacts due to invalid stage
15702    * clipping or due to incorrect culling.
15703    *
15704    * Previously we checked in clutter_actor_paint(), but at that time
15705    * we may already be using a stage clip that could be derived from
15706    * an invalid paint-volume. We used to try and handle that by
15707    * queuing a follow up, unclipped, redraw but still the previous
15708    * checking wasn't enough to catch invalid volumes involved in
15709    * culling (considering that containers may derive their volume from
15710    * children that haven't yet been painted)
15711    *
15712    * Longer term, improved solutions could be:
15713    * - Disallow painting in the paint signal, only allow using it
15714    *   for tracking when paints happen. We can add another API that
15715    *   allows monkey patching the paint of arbitrary actors but in a
15716    *   more controlled way and that also supports modifying the
15717    *   paint-volume.
15718    * - If we could be notified somehow when signal handlers are
15719    *   connected we wouldn't have to poll for handlers like this.
15720    */
15721   if (g_signal_has_handler_pending (self,
15722                                     actor_signals[PAINT],
15723                                     0,
15724                                     TRUE))
15725     {
15726       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15727                     "Actor has \"paint\" signal handlers",
15728                     _clutter_actor_get_debug_name (self));
15729       return FALSE;
15730     }
15731
15732   _clutter_paint_volume_init_static (pv, self);
15733
15734   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15735     {
15736       clutter_paint_volume_free (pv);
15737       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15738                     "Actor failed to report a volume",
15739                     _clutter_actor_get_debug_name (self));
15740       return FALSE;
15741     }
15742
15743   /* since effects can modify the paint volume, we allow them to actually
15744    * do this by making get_paint_volume() "context sensitive"
15745    */
15746   if (priv->effects != NULL)
15747     {
15748       if (priv->current_effect != NULL)
15749         {
15750           const GList *effects, *l;
15751
15752           /* if we are being called from within the paint sequence of
15753            * an actor, get the paint volume up to the current effect
15754            */
15755           effects = _clutter_meta_group_peek_metas (priv->effects);
15756           for (l = effects;
15757                l != NULL || (l != NULL && l->data != priv->current_effect);
15758                l = l->next)
15759             {
15760               if (!_clutter_effect_get_paint_volume (l->data, pv))
15761                 {
15762                   clutter_paint_volume_free (pv);
15763                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15764                                 "Effect (%s) failed to report a volume",
15765                                 _clutter_actor_get_debug_name (self),
15766                                 _clutter_actor_meta_get_debug_name (l->data));
15767                   return FALSE;
15768                 }
15769             }
15770         }
15771       else
15772         {
15773           const GList *effects, *l;
15774
15775           /* otherwise, get the cumulative volume */
15776           effects = _clutter_meta_group_peek_metas (priv->effects);
15777           for (l = effects; l != NULL; l = l->next)
15778             if (!_clutter_effect_get_paint_volume (l->data, pv))
15779               {
15780                 clutter_paint_volume_free (pv);
15781                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15782                               "Effect (%s) failed to report a volume",
15783                               _clutter_actor_get_debug_name (self),
15784                               _clutter_actor_meta_get_debug_name (l->data));
15785                 return FALSE;
15786               }
15787         }
15788     }
15789
15790   return TRUE;
15791 }
15792
15793 /* The public clutter_actor_get_paint_volume API returns a const
15794  * pointer since we return a pointer directly to the cached
15795  * PaintVolume associated with the actor and don't want the user to
15796  * inadvertently modify it, but for internal uses we sometimes need
15797  * access to the same PaintVolume but need to apply some book-keeping
15798  * modifications to it so we don't want a const pointer.
15799  */
15800 static ClutterPaintVolume *
15801 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15802 {
15803   ClutterActorPrivate *priv;
15804
15805   priv = self->priv;
15806
15807   if (priv->paint_volume_valid)
15808     clutter_paint_volume_free (&priv->paint_volume);
15809
15810   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15811     {
15812       priv->paint_volume_valid = TRUE;
15813       return &priv->paint_volume;
15814     }
15815   else
15816     {
15817       priv->paint_volume_valid = FALSE;
15818       return NULL;
15819     }
15820 }
15821
15822 /**
15823  * clutter_actor_get_paint_volume:
15824  * @self: a #ClutterActor
15825  *
15826  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15827  * when a paint volume can't be determined.
15828  *
15829  * The paint volume is defined as the 3D space occupied by an actor
15830  * when being painted.
15831  *
15832  * This function will call the <function>get_paint_volume()</function>
15833  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15834  * should not usually care about overriding the default implementation,
15835  * unless they are, for instance: painting outside their allocation, or
15836  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15837  * 3D depth).
15838  *
15839  * <note>2D actors overriding <function>get_paint_volume()</function>
15840  * ensure their volume has a depth of 0. (This will be true so long as
15841  * you don't call clutter_paint_volume_set_depth().)</note>
15842  *
15843  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15844  *   or %NULL if no volume could be determined. The returned pointer
15845  *   is not guaranteed to be valid across multiple frames; if you want
15846  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15847  *
15848  * Since: 1.6
15849  */
15850 const ClutterPaintVolume *
15851 clutter_actor_get_paint_volume (ClutterActor *self)
15852 {
15853   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15854
15855   return _clutter_actor_get_paint_volume_mutable (self);
15856 }
15857
15858 /**
15859  * clutter_actor_get_transformed_paint_volume:
15860  * @self: a #ClutterActor
15861  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15862  *    (or %NULL for the stage)
15863  *
15864  * Retrieves the 3D paint volume of an actor like
15865  * clutter_actor_get_paint_volume() does (Please refer to the
15866  * documentation of clutter_actor_get_paint_volume() for more
15867  * details.) and it additionally transforms the paint volume into the
15868  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15869  * is passed for @relative_to_ancestor)
15870  *
15871  * This can be used by containers that base their paint volume on
15872  * the volume of their children. Such containers can query the
15873  * transformed paint volume of all of its children and union them
15874  * together using clutter_paint_volume_union().
15875  *
15876  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15877  *   or %NULL if no volume could be determined. The returned pointer is
15878  *   not guaranteed to be valid across multiple frames; if you wish to
15879  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15880  *
15881  * Since: 1.6
15882  */
15883 const ClutterPaintVolume *
15884 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15885                                             ClutterActor *relative_to_ancestor)
15886 {
15887   const ClutterPaintVolume *volume;
15888   ClutterActor *stage;
15889   ClutterPaintVolume *transformed_volume;
15890
15891   stage = _clutter_actor_get_stage_internal (self);
15892   if (G_UNLIKELY (stage == NULL))
15893     return NULL;
15894
15895   if (relative_to_ancestor == NULL)
15896     relative_to_ancestor = stage;
15897
15898   volume = clutter_actor_get_paint_volume (self);
15899   if (volume == NULL)
15900     return NULL;
15901
15902   transformed_volume =
15903     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15904
15905   _clutter_paint_volume_copy_static (volume, transformed_volume);
15906
15907   _clutter_paint_volume_transform_relative (transformed_volume,
15908                                             relative_to_ancestor);
15909
15910   return transformed_volume;
15911 }
15912
15913 /**
15914  * clutter_actor_get_paint_box:
15915  * @self: a #ClutterActor
15916  * @box: (out): return location for a #ClutterActorBox
15917  *
15918  * Retrieves the paint volume of the passed #ClutterActor, and
15919  * transforms it into a 2D bounding box in stage coordinates.
15920  *
15921  * This function is useful to determine the on screen area occupied by
15922  * the actor. The box is only an approximation and may often be
15923  * considerably larger due to the optimizations used to calculate the
15924  * box. The box is never smaller though, so it can reliably be used
15925  * for culling.
15926  *
15927  * There are times when a 2D paint box can't be determined, e.g.
15928  * because the actor isn't yet parented under a stage or because
15929  * the actor is unable to determine a paint volume.
15930  *
15931  * Return value: %TRUE if a 2D paint box could be determined, else
15932  * %FALSE.
15933  *
15934  * Since: 1.6
15935  */
15936 gboolean
15937 clutter_actor_get_paint_box (ClutterActor    *self,
15938                              ClutterActorBox *box)
15939 {
15940   ClutterActor *stage;
15941   ClutterPaintVolume *pv;
15942
15943   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15944   g_return_val_if_fail (box != NULL, FALSE);
15945
15946   stage = _clutter_actor_get_stage_internal (self);
15947   if (G_UNLIKELY (!stage))
15948     return FALSE;
15949
15950   pv = _clutter_actor_get_paint_volume_mutable (self);
15951   if (G_UNLIKELY (!pv))
15952     return FALSE;
15953
15954   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15955
15956   return TRUE;
15957 }
15958
15959 /**
15960  * clutter_actor_has_overlaps:
15961  * @self: A #ClutterActor
15962  *
15963  * Asks the actor's implementation whether it may contain overlapping
15964  * primitives.
15965  *
15966  * For example; Clutter may use this to determine whether the painting
15967  * should be redirected to an offscreen buffer to correctly implement
15968  * the opacity property.
15969  *
15970  * Custom actors can override the default response by implementing the
15971  * #ClutterActor <function>has_overlaps</function> virtual function. See
15972  * clutter_actor_set_offscreen_redirect() for more information.
15973  *
15974  * Return value: %TRUE if the actor may have overlapping primitives, and
15975  *   %FALSE otherwise
15976  *
15977  * Since: 1.8
15978  */
15979 gboolean
15980 clutter_actor_has_overlaps (ClutterActor *self)
15981 {
15982   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15983
15984   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15985 }
15986
15987 /**
15988  * clutter_actor_has_effects:
15989  * @self: A #ClutterActor
15990  *
15991  * Returns whether the actor has any effects applied.
15992  *
15993  * Return value: %TRUE if the actor has any effects,
15994  *   %FALSE otherwise
15995  *
15996  * Since: 1.10
15997  */
15998 gboolean
15999 clutter_actor_has_effects (ClutterActor *self)
16000 {
16001   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16002
16003   if (self->priv->effects == NULL)
16004     return FALSE;
16005
16006   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
16007 }
16008
16009 /**
16010  * clutter_actor_has_constraints:
16011  * @self: A #ClutterActor
16012  *
16013  * Returns whether the actor has any constraints applied.
16014  *
16015  * Return value: %TRUE if the actor has any constraints,
16016  *   %FALSE otherwise
16017  *
16018  * Since: 1.10
16019  */
16020 gboolean
16021 clutter_actor_has_constraints (ClutterActor *self)
16022 {
16023   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16024
16025   return self->priv->constraints != NULL;
16026 }
16027
16028 /**
16029  * clutter_actor_has_actions:
16030  * @self: A #ClutterActor
16031  *
16032  * Returns whether the actor has any actions applied.
16033  *
16034  * Return value: %TRUE if the actor has any actions,
16035  *   %FALSE otherwise
16036  *
16037  * Since: 1.10
16038  */
16039 gboolean
16040 clutter_actor_has_actions (ClutterActor *self)
16041 {
16042   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
16043
16044   return self->priv->actions != NULL;
16045 }
16046
16047 /**
16048  * clutter_actor_get_n_children:
16049  * @self: a #ClutterActor
16050  *
16051  * Retrieves the number of children of @self.
16052  *
16053  * Return value: the number of children of an actor
16054  *
16055  * Since: 1.10
16056  */
16057 gint
16058 clutter_actor_get_n_children (ClutterActor *self)
16059 {
16060   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
16061
16062   return self->priv->n_children;
16063 }
16064
16065 /**
16066  * clutter_actor_get_child_at_index:
16067  * @self: a #ClutterActor
16068  * @index_: the position in the list of children
16069  *
16070  * Retrieves the actor at the given @index_ inside the list of
16071  * children of @self.
16072  *
16073  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16074  *
16075  * Since: 1.10
16076  */
16077 ClutterActor *
16078 clutter_actor_get_child_at_index (ClutterActor *self,
16079                                   gint          index_)
16080 {
16081   ClutterActor *iter;
16082   int i;
16083
16084   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16085   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
16086
16087   for (iter = self->priv->first_child, i = 0;
16088        iter != NULL && i < index_;
16089        iter = iter->priv->next_sibling, i += 1)
16090     ;
16091
16092   return iter;
16093 }
16094
16095 /*< private >
16096  * _clutter_actor_foreach_child:
16097  * @actor: The actor whos children you want to iterate
16098  * @callback: The function to call for each child
16099  * @user_data: Private data to pass to @callback
16100  *
16101  * Calls a given @callback once for each child of the specified @actor and
16102  * passing the @user_data pointer each time.
16103  *
16104  * Return value: returns %TRUE if all children were iterated, else
16105  *    %FALSE if a callback broke out of iteration early.
16106  */
16107 gboolean
16108 _clutter_actor_foreach_child (ClutterActor           *self,
16109                               ClutterForeachCallback  callback,
16110                               gpointer                user_data)
16111 {
16112   ClutterActor *iter;
16113   gboolean cont;
16114
16115   if (self->priv->first_child == NULL)
16116     return TRUE;
16117
16118   cont = TRUE;
16119   iter = self->priv->first_child;
16120
16121   /* we use this form so that it's safe to change the children
16122    * list while iterating it
16123    */
16124   while (cont && iter != NULL)
16125     {
16126       ClutterActor *next = iter->priv->next_sibling;
16127
16128       cont = callback (iter, user_data);
16129
16130       iter = next;
16131     }
16132
16133   return cont;
16134 }
16135
16136 #if 0
16137 /* For debugging purposes this gives us a simple way to print out
16138  * the scenegraph e.g in gdb using:
16139  * [|
16140  *   _clutter_actor_traverse (stage,
16141  *                            0,
16142  *                            clutter_debug_print_actor_cb,
16143  *                            NULL,
16144  *                            NULL);
16145  * |]
16146  */
16147 static ClutterActorTraverseVisitFlags
16148 clutter_debug_print_actor_cb (ClutterActor *actor,
16149                               int depth,
16150                               void *user_data)
16151 {
16152   g_print ("%*s%s:%p\n",
16153            depth * 2, "",
16154            _clutter_actor_get_debug_name (actor),
16155            actor);
16156
16157   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16158 }
16159 #endif
16160
16161 static void
16162 _clutter_actor_traverse_breadth (ClutterActor           *actor,
16163                                  ClutterTraverseCallback callback,
16164                                  gpointer                user_data)
16165 {
16166   GQueue *queue = g_queue_new ();
16167   ClutterActor dummy;
16168   int current_depth = 0;
16169
16170   g_queue_push_tail (queue, actor);
16171   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
16172
16173   while ((actor = g_queue_pop_head (queue)))
16174     {
16175       ClutterActorTraverseVisitFlags flags;
16176
16177       if (actor == &dummy)
16178         {
16179           current_depth++;
16180           g_queue_push_tail (queue, &dummy);
16181           continue;
16182         }
16183
16184       flags = callback (actor, current_depth, user_data);
16185       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16186         break;
16187       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16188         {
16189           ClutterActor *iter;
16190
16191           for (iter = actor->priv->first_child;
16192                iter != NULL;
16193                iter = iter->priv->next_sibling)
16194             {
16195               g_queue_push_tail (queue, iter);
16196             }
16197         }
16198     }
16199
16200   g_queue_free (queue);
16201 }
16202
16203 static ClutterActorTraverseVisitFlags
16204 _clutter_actor_traverse_depth (ClutterActor           *actor,
16205                                ClutterTraverseCallback before_children_callback,
16206                                ClutterTraverseCallback after_children_callback,
16207                                int                     current_depth,
16208                                gpointer                user_data)
16209 {
16210   ClutterActorTraverseVisitFlags flags;
16211
16212   flags = before_children_callback (actor, current_depth, user_data);
16213   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16214     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16215
16216   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
16217     {
16218       ClutterActor *iter;
16219
16220       for (iter = actor->priv->first_child;
16221            iter != NULL;
16222            iter = iter->priv->next_sibling)
16223         {
16224           flags = _clutter_actor_traverse_depth (iter,
16225                                                  before_children_callback,
16226                                                  after_children_callback,
16227                                                  current_depth + 1,
16228                                                  user_data);
16229
16230           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
16231             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
16232         }
16233     }
16234
16235   if (after_children_callback)
16236     return after_children_callback (actor, current_depth, user_data);
16237   else
16238     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
16239 }
16240
16241 /* _clutter_actor_traverse:
16242  * @actor: The actor to start traversing the graph from
16243  * @flags: These flags may affect how the traversal is done
16244  * @before_children_callback: A function to call before visiting the
16245  *   children of the current actor.
16246  * @after_children_callback: A function to call after visiting the
16247  *   children of the current actor. (Ignored if
16248  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
16249  * @user_data: The private data to pass to the callbacks
16250  *
16251  * Traverses the scenegraph starting at the specified @actor and
16252  * descending through all its children and its children's children.
16253  * For each actor traversed @before_children_callback and
16254  * @after_children_callback are called with the specified
16255  * @user_data, before and after visiting that actor's children.
16256  *
16257  * The callbacks can return flags that affect the ongoing traversal
16258  * such as by skipping over an actors children or bailing out of
16259  * any further traversing.
16260  */
16261 void
16262 _clutter_actor_traverse (ClutterActor              *actor,
16263                          ClutterActorTraverseFlags  flags,
16264                          ClutterTraverseCallback    before_children_callback,
16265                          ClutterTraverseCallback    after_children_callback,
16266                          gpointer                   user_data)
16267 {
16268   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
16269     _clutter_actor_traverse_breadth (actor,
16270                                      before_children_callback,
16271                                      user_data);
16272   else /* DEPTH_FIRST */
16273     _clutter_actor_traverse_depth (actor,
16274                                    before_children_callback,
16275                                    after_children_callback,
16276                                    0, /* start depth */
16277                                    user_data);
16278 }
16279
16280 static void
16281 on_layout_manager_changed (ClutterLayoutManager *manager,
16282                            ClutterActor         *self)
16283 {
16284   clutter_actor_queue_relayout (self);
16285 }
16286
16287 /**
16288  * clutter_actor_set_layout_manager:
16289  * @self: a #ClutterActor
16290  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
16291  *
16292  * Sets the #ClutterLayoutManager delegate object that will be used to
16293  * lay out the children of @self.
16294  *
16295  * The #ClutterActor will take a reference on the passed @manager which
16296  * will be released either when the layout manager is removed, or when
16297  * the actor is destroyed.
16298  *
16299  * Since: 1.10
16300  */
16301 void
16302 clutter_actor_set_layout_manager (ClutterActor         *self,
16303                                   ClutterLayoutManager *manager)
16304 {
16305   ClutterActorPrivate *priv;
16306
16307   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16308   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16309
16310   priv = self->priv;
16311
16312   if (priv->layout_manager != NULL)
16313     {
16314       g_signal_handlers_disconnect_by_func (priv->layout_manager,
16315                                             G_CALLBACK (on_layout_manager_changed),
16316                                             self);
16317       clutter_layout_manager_set_container (priv->layout_manager, NULL);
16318       g_clear_object (&priv->layout_manager);
16319     }
16320
16321   priv->layout_manager = manager;
16322
16323   if (priv->layout_manager != NULL)
16324     {
16325       g_object_ref_sink (priv->layout_manager);
16326       clutter_layout_manager_set_container (priv->layout_manager,
16327                                             CLUTTER_CONTAINER (self));
16328       g_signal_connect (priv->layout_manager, "layout-changed",
16329                         G_CALLBACK (on_layout_manager_changed),
16330                         self);
16331     }
16332
16333   clutter_actor_queue_relayout (self);
16334
16335   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16336 }
16337
16338 /**
16339  * clutter_actor_get_layout_manager:
16340  * @self: a #ClutterActor
16341  *
16342  * Retrieves the #ClutterLayoutManager used by @self.
16343  *
16344  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16345  *   or %NULL
16346  *
16347  * Since: 1.10
16348  */
16349 ClutterLayoutManager *
16350 clutter_actor_get_layout_manager (ClutterActor *self)
16351 {
16352   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16353
16354   return self->priv->layout_manager;
16355 }
16356
16357 static const ClutterLayoutInfo default_layout_info = {
16358   CLUTTER_POINT_INIT_ZERO,      /* fixed-pos */
16359   { 0, 0, 0, 0 },               /* margin */
16360   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
16361   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
16362   FALSE, FALSE,                 /* expand */
16363   CLUTTER_SIZE_INIT_ZERO,       /* minimum */
16364   CLUTTER_SIZE_INIT_ZERO,       /* natural */
16365 };
16366
16367 static void
16368 layout_info_free (gpointer data)
16369 {
16370   if (G_LIKELY (data != NULL))
16371     g_slice_free (ClutterLayoutInfo, data);
16372 }
16373
16374 /*< private >
16375  * _clutter_actor_peek_layout_info:
16376  * @self: a #ClutterActor
16377  *
16378  * Retrieves a pointer to the ClutterLayoutInfo structure.
16379  *
16380  * If the actor does not have a ClutterLayoutInfo associated to it, %NULL is returned.
16381  *
16382  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16383  */
16384 ClutterLayoutInfo *
16385 _clutter_actor_peek_layout_info (ClutterActor *self)
16386 {
16387   return g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16388 }
16389
16390 /*< private >
16391  * _clutter_actor_get_layout_info:
16392  * @self: a #ClutterActor
16393  *
16394  * Retrieves a pointer to the ClutterLayoutInfo structure.
16395  *
16396  * If the actor does not have a ClutterLayoutInfo associated to it, one
16397  * will be created and initialized to the default values.
16398  *
16399  * This function should be used for setters.
16400  *
16401  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16402  * instead.
16403  *
16404  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16405  */
16406 ClutterLayoutInfo *
16407 _clutter_actor_get_layout_info (ClutterActor *self)
16408 {
16409   ClutterLayoutInfo *retval;
16410
16411   retval = _clutter_actor_peek_layout_info (self);
16412   if (retval == NULL)
16413     {
16414       retval = g_slice_new (ClutterLayoutInfo);
16415
16416       *retval = default_layout_info;
16417
16418       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16419                                retval,
16420                                layout_info_free);
16421     }
16422
16423   return retval;
16424 }
16425
16426 /*< private >
16427  * _clutter_actor_get_layout_info_or_defaults:
16428  * @self: a #ClutterActor
16429  *
16430  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16431  *
16432  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16433  * then the default structure will be returned.
16434  *
16435  * This function should only be used for getters.
16436  *
16437  * Return value: a const pointer to the ClutterLayoutInfo structure
16438  */
16439 const ClutterLayoutInfo *
16440 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16441 {
16442   const ClutterLayoutInfo *info;
16443
16444   info = _clutter_actor_peek_layout_info (self);
16445   if (info == NULL)
16446     return &default_layout_info;
16447
16448   return info;
16449 }
16450
16451 /**
16452  * clutter_actor_set_x_align:
16453  * @self: a #ClutterActor
16454  * @x_align: the horizontal alignment policy
16455  *
16456  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16457  * actor received extra horizontal space.
16458  *
16459  * See also the #ClutterActor:x-align property.
16460  *
16461  * Since: 1.10
16462  */
16463 void
16464 clutter_actor_set_x_align (ClutterActor      *self,
16465                            ClutterActorAlign  x_align)
16466 {
16467   ClutterLayoutInfo *info;
16468
16469   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16470
16471   info = _clutter_actor_get_layout_info (self);
16472
16473   if (info->x_align != x_align)
16474     {
16475       info->x_align = x_align;
16476
16477       clutter_actor_queue_relayout (self);
16478
16479       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16480     }
16481 }
16482
16483 /**
16484  * clutter_actor_get_x_align:
16485  * @self: a #ClutterActor
16486  *
16487  * Retrieves the horizontal alignment policy set using
16488  * clutter_actor_set_x_align().
16489  *
16490  * Return value: the horizontal alignment policy.
16491  *
16492  * Since: 1.10
16493  */
16494 ClutterActorAlign
16495 clutter_actor_get_x_align (ClutterActor *self)
16496 {
16497   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16498
16499   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16500 }
16501
16502 /**
16503  * clutter_actor_set_y_align:
16504  * @self: a #ClutterActor
16505  * @y_align: the vertical alignment policy
16506  *
16507  * Sets the vertical alignment policy of a #ClutterActor, in case the
16508  * actor received extra vertical space.
16509  *
16510  * See also the #ClutterActor:y-align property.
16511  *
16512  * Since: 1.10
16513  */
16514 void
16515 clutter_actor_set_y_align (ClutterActor      *self,
16516                            ClutterActorAlign  y_align)
16517 {
16518   ClutterLayoutInfo *info;
16519
16520   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16521
16522   info = _clutter_actor_get_layout_info (self);
16523
16524   if (info->y_align != y_align)
16525     {
16526       info->y_align = y_align;
16527
16528       clutter_actor_queue_relayout (self);
16529
16530       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16531     }
16532 }
16533
16534 /**
16535  * clutter_actor_get_y_align:
16536  * @self: a #ClutterActor
16537  *
16538  * Retrieves the vertical alignment policy set using
16539  * clutter_actor_set_y_align().
16540  *
16541  * Return value: the vertical alignment policy.
16542  *
16543  * Since: 1.10
16544  */
16545 ClutterActorAlign
16546 clutter_actor_get_y_align (ClutterActor *self)
16547 {
16548   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16549
16550   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16551 }
16552
16553 /**
16554  * clutter_actor_set_margin:
16555  * @self: a #ClutterActor
16556  * @margin: a #ClutterMargin
16557  *
16558  * Sets all the components of the margin of a #ClutterActor.
16559  *
16560  * Since: 1.10
16561  */
16562 void
16563 clutter_actor_set_margin (ClutterActor        *self,
16564                           const ClutterMargin *margin)
16565 {
16566   ClutterLayoutInfo *info;
16567   gboolean changed;
16568   GObject *obj;
16569
16570   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16571   g_return_if_fail (margin != NULL);
16572
16573   obj = G_OBJECT (self);
16574   changed = FALSE;
16575
16576   g_object_freeze_notify (obj);
16577
16578   info = _clutter_actor_get_layout_info (self);
16579
16580   if (info->margin.top != margin->top)
16581     {
16582       info->margin.top = margin->top;
16583       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16584       changed = TRUE;
16585     }
16586
16587   if (info->margin.right != margin->right)
16588     {
16589       info->margin.right = margin->right;
16590       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16591       changed = TRUE;
16592     }
16593
16594   if (info->margin.bottom != margin->bottom)
16595     {
16596       info->margin.bottom = margin->bottom;
16597       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16598       changed = TRUE;
16599     }
16600
16601   if (info->margin.left != margin->left)
16602     {
16603       info->margin.left = margin->left;
16604       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16605       changed = TRUE;
16606     }
16607
16608   if (changed)
16609     clutter_actor_queue_relayout (self);
16610
16611   g_object_thaw_notify (obj);
16612 }
16613
16614 /**
16615  * clutter_actor_get_margin:
16616  * @self: a #ClutterActor
16617  * @margin: (out caller-allocates): return location for a #ClutterMargin
16618  *
16619  * Retrieves all the components of the margin of a #ClutterActor.
16620  *
16621  * Since: 1.10
16622  */
16623 void
16624 clutter_actor_get_margin (ClutterActor  *self,
16625                           ClutterMargin *margin)
16626 {
16627   const ClutterLayoutInfo *info;
16628
16629   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16630   g_return_if_fail (margin != NULL);
16631
16632   info = _clutter_actor_get_layout_info_or_defaults (self);
16633
16634   *margin = info->margin;
16635 }
16636
16637 /**
16638  * clutter_actor_set_margin_top:
16639  * @self: a #ClutterActor
16640  * @margin: the top margin
16641  *
16642  * Sets the margin from the top of a #ClutterActor.
16643  *
16644  * Since: 1.10
16645  */
16646 void
16647 clutter_actor_set_margin_top (ClutterActor *self,
16648                               gfloat        margin)
16649 {
16650   ClutterLayoutInfo *info;
16651
16652   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16653   g_return_if_fail (margin >= 0.f);
16654
16655   info = _clutter_actor_get_layout_info (self);
16656
16657   if (info->margin.top == margin)
16658     return;
16659
16660   info->margin.top = margin;
16661
16662   clutter_actor_queue_relayout (self);
16663
16664   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16665 }
16666
16667 /**
16668  * clutter_actor_get_margin_top:
16669  * @self: a #ClutterActor
16670  *
16671  * Retrieves the top margin of a #ClutterActor.
16672  *
16673  * Return value: the top margin
16674  *
16675  * Since: 1.10
16676  */
16677 gfloat
16678 clutter_actor_get_margin_top (ClutterActor *self)
16679 {
16680   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16681
16682   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16683 }
16684
16685 /**
16686  * clutter_actor_set_margin_bottom:
16687  * @self: a #ClutterActor
16688  * @margin: the bottom margin
16689  *
16690  * Sets the margin from the bottom of a #ClutterActor.
16691  *
16692  * Since: 1.10
16693  */
16694 void
16695 clutter_actor_set_margin_bottom (ClutterActor *self,
16696                                  gfloat        margin)
16697 {
16698   ClutterLayoutInfo *info;
16699
16700   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16701   g_return_if_fail (margin >= 0.f);
16702
16703   info = _clutter_actor_get_layout_info (self);
16704
16705   if (info->margin.bottom == margin)
16706     return;
16707
16708   info->margin.bottom = margin;
16709
16710   clutter_actor_queue_relayout (self);
16711
16712   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16713 }
16714
16715 /**
16716  * clutter_actor_get_margin_bottom:
16717  * @self: a #ClutterActor
16718  *
16719  * Retrieves the bottom margin of a #ClutterActor.
16720  *
16721  * Return value: the bottom margin
16722  *
16723  * Since: 1.10
16724  */
16725 gfloat
16726 clutter_actor_get_margin_bottom (ClutterActor *self)
16727 {
16728   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16729
16730   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16731 }
16732
16733 /**
16734  * clutter_actor_set_margin_left:
16735  * @self: a #ClutterActor
16736  * @margin: the left margin
16737  *
16738  * Sets the margin from the left of a #ClutterActor.
16739  *
16740  * Since: 1.10
16741  */
16742 void
16743 clutter_actor_set_margin_left (ClutterActor *self,
16744                                gfloat        margin)
16745 {
16746   ClutterLayoutInfo *info;
16747
16748   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16749   g_return_if_fail (margin >= 0.f);
16750
16751   info = _clutter_actor_get_layout_info (self);
16752
16753   if (info->margin.left == margin)
16754     return;
16755
16756   info->margin.left = margin;
16757
16758   clutter_actor_queue_relayout (self);
16759
16760   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16761 }
16762
16763 /**
16764  * clutter_actor_get_margin_left:
16765  * @self: a #ClutterActor
16766  *
16767  * Retrieves the left margin of a #ClutterActor.
16768  *
16769  * Return value: the left margin
16770  *
16771  * Since: 1.10
16772  */
16773 gfloat
16774 clutter_actor_get_margin_left (ClutterActor *self)
16775 {
16776   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16777
16778   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16779 }
16780
16781 /**
16782  * clutter_actor_set_margin_right:
16783  * @self: a #ClutterActor
16784  * @margin: the right margin
16785  *
16786  * Sets the margin from the right of a #ClutterActor.
16787  *
16788  * Since: 1.10
16789  */
16790 void
16791 clutter_actor_set_margin_right (ClutterActor *self,
16792                                 gfloat        margin)
16793 {
16794   ClutterLayoutInfo *info;
16795
16796   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16797   g_return_if_fail (margin >= 0.f);
16798
16799   info = _clutter_actor_get_layout_info (self);
16800
16801   if (info->margin.right == margin)
16802     return;
16803
16804   info->margin.right = margin;
16805
16806   clutter_actor_queue_relayout (self);
16807
16808   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16809 }
16810
16811 /**
16812  * clutter_actor_get_margin_right:
16813  * @self: a #ClutterActor
16814  *
16815  * Retrieves the right margin of a #ClutterActor.
16816  *
16817  * Return value: the right margin
16818  *
16819  * Since: 1.10
16820  */
16821 gfloat
16822 clutter_actor_get_margin_right (ClutterActor *self)
16823 {
16824   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16825
16826   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16827 }
16828
16829 static inline void
16830 clutter_actor_set_background_color_internal (ClutterActor *self,
16831                                              const ClutterColor *color)
16832 {
16833   ClutterActorPrivate *priv = self->priv;
16834   GObject *obj;
16835
16836   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16837     return;
16838
16839   obj = G_OBJECT (self);
16840
16841   priv->bg_color = *color;
16842   priv->bg_color_set = TRUE;
16843
16844   clutter_actor_queue_redraw (self);
16845
16846   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16847   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16848 }
16849
16850 /**
16851  * clutter_actor_set_background_color:
16852  * @self: a #ClutterActor
16853  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16854  *  set color
16855  *
16856  * Sets the background color of a #ClutterActor.
16857  *
16858  * The background color will be used to cover the whole allocation of the
16859  * actor. The default background color of an actor is transparent.
16860  *
16861  * To check whether an actor has a background color, you can use the
16862  * #ClutterActor:background-color-set actor property.
16863  *
16864  * The #ClutterActor:background-color property is animatable.
16865  *
16866  * Since: 1.10
16867  */
16868 void
16869 clutter_actor_set_background_color (ClutterActor       *self,
16870                                     const ClutterColor *color)
16871 {
16872   ClutterActorPrivate *priv;
16873   GObject *obj;
16874   GParamSpec *bg_color_pspec;
16875
16876   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16877
16878   obj = G_OBJECT (self);
16879
16880   priv = self->priv;
16881
16882   if (color == NULL)
16883     {
16884       priv->bg_color_set = FALSE;
16885       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16886       clutter_actor_queue_redraw (self);
16887       return;
16888     }
16889
16890   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16891   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16892     {
16893       _clutter_actor_create_transition (self, bg_color_pspec,
16894                                         &priv->bg_color,
16895                                         color);
16896     }
16897   else
16898     _clutter_actor_update_transition (self, bg_color_pspec, color);
16899
16900   clutter_actor_queue_redraw (self);
16901 }
16902
16903 /**
16904  * clutter_actor_get_background_color:
16905  * @self: a #ClutterActor
16906  * @color: (out caller-allocates): return location for a #ClutterColor
16907  *
16908  * Retrieves the color set using clutter_actor_set_background_color().
16909  *
16910  * Since: 1.10
16911  */
16912 void
16913 clutter_actor_get_background_color (ClutterActor *self,
16914                                     ClutterColor *color)
16915 {
16916   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16917   g_return_if_fail (color != NULL);
16918
16919   *color = self->priv->bg_color;
16920 }
16921
16922 /**
16923  * clutter_actor_get_previous_sibling:
16924  * @self: a #ClutterActor
16925  *
16926  * Retrieves the sibling of @self that comes before it in the list
16927  * of children of @self's parent.
16928  *
16929  * The returned pointer is only valid until the scene graph changes; it
16930  * is not safe to modify the list of children of @self while iterating
16931  * it.
16932  *
16933  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16934  *
16935  * Since: 1.10
16936  */
16937 ClutterActor *
16938 clutter_actor_get_previous_sibling (ClutterActor *self)
16939 {
16940   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16941
16942   return self->priv->prev_sibling;
16943 }
16944
16945 /**
16946  * clutter_actor_get_next_sibling:
16947  * @self: a #ClutterActor
16948  *
16949  * Retrieves the sibling of @self that comes after it in the list
16950  * of children of @self's parent.
16951  *
16952  * The returned pointer is only valid until the scene graph changes; it
16953  * is not safe to modify the list of children of @self while iterating
16954  * it.
16955  *
16956  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16957  *
16958  * Since: 1.10
16959  */
16960 ClutterActor *
16961 clutter_actor_get_next_sibling (ClutterActor *self)
16962 {
16963   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16964
16965   return self->priv->next_sibling;
16966 }
16967
16968 /**
16969  * clutter_actor_get_first_child:
16970  * @self: a #ClutterActor
16971  *
16972  * Retrieves the first child of @self.
16973  *
16974  * The returned pointer is only valid until the scene graph changes; it
16975  * is not safe to modify the list of children of @self while iterating
16976  * it.
16977  *
16978  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16979  *
16980  * Since: 1.10
16981  */
16982 ClutterActor *
16983 clutter_actor_get_first_child (ClutterActor *self)
16984 {
16985   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16986
16987   return self->priv->first_child;
16988 }
16989
16990 /**
16991  * clutter_actor_get_last_child:
16992  * @self: a #ClutterActor
16993  *
16994  * Retrieves the last child of @self.
16995  *
16996  * The returned pointer is only valid until the scene graph changes; it
16997  * is not safe to modify the list of children of @self while iterating
16998  * it.
16999  *
17000  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
17001  *
17002  * Since: 1.10
17003  */
17004 ClutterActor *
17005 clutter_actor_get_last_child (ClutterActor *self)
17006 {
17007   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17008
17009   return self->priv->last_child;
17010 }
17011
17012 /* easy way to have properly named fields instead of the dummy ones
17013  * we use in the public structure
17014  */
17015 typedef struct _RealActorIter
17016 {
17017   ClutterActor *root;           /* dummy1 */
17018   ClutterActor *current;        /* dummy2 */
17019   gpointer padding_1;           /* dummy3 */
17020   gint age;                     /* dummy4 */
17021   gpointer padding_2;           /* dummy5 */
17022 } RealActorIter;
17023
17024 /**
17025  * clutter_actor_iter_init:
17026  * @iter: a #ClutterActorIter
17027  * @root: a #ClutterActor
17028  *
17029  * Initializes a #ClutterActorIter, which can then be used to iterate
17030  * efficiently over a section of the scene graph, and associates it
17031  * with @root.
17032  *
17033  * Modifying the scene graph section that contains @root will invalidate
17034  * the iterator.
17035  *
17036  * |[
17037  *   ClutterActorIter iter;
17038  *   ClutterActor *child;
17039  *
17040  *   clutter_actor_iter_init (&iter, container);
17041  *   while (clutter_actor_iter_next (&iter, &child))
17042  *     {
17043  *       /&ast; do something with child &ast;/
17044  *     }
17045  * ]|
17046  *
17047  * Since: 1.10
17048  */
17049 void
17050 clutter_actor_iter_init (ClutterActorIter *iter,
17051                          ClutterActor     *root)
17052 {
17053   RealActorIter *ri = (RealActorIter *) iter;
17054
17055   g_return_if_fail (iter != NULL);
17056   g_return_if_fail (CLUTTER_IS_ACTOR (root));
17057
17058   ri->root = root;
17059   ri->current = NULL;
17060   ri->age = root->priv->age;
17061 }
17062
17063 /**
17064  * clutter_actor_iter_next:
17065  * @iter: a #ClutterActorIter
17066  * @child: (out): return location for a #ClutterActor
17067  *
17068  * Advances the @iter and retrieves the next child of the root #ClutterActor
17069  * that was used to initialize the #ClutterActorIterator.
17070  *
17071  * If the iterator can advance, this function returns %TRUE and sets the
17072  * @child argument.
17073  *
17074  * If the iterator cannot advance, this function returns %FALSE, and
17075  * the contents of @child are undefined.
17076  *
17077  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17078  *
17079  * Since: 1.10
17080  */
17081 gboolean
17082 clutter_actor_iter_next (ClutterActorIter  *iter,
17083                          ClutterActor     **child)
17084 {
17085   RealActorIter *ri = (RealActorIter *) iter;
17086
17087   g_return_val_if_fail (iter != NULL, FALSE);
17088   g_return_val_if_fail (ri->root != NULL, FALSE);
17089 #ifndef G_DISABLE_ASSERT
17090   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17091 #endif
17092
17093   if (ri->current == NULL)
17094     ri->current = ri->root->priv->first_child;
17095   else
17096     ri->current = ri->current->priv->next_sibling;
17097
17098   if (child != NULL)
17099     *child = ri->current;
17100
17101   return ri->current != NULL;
17102 }
17103
17104 /**
17105  * clutter_actor_iter_prev:
17106  * @iter: a #ClutterActorIter
17107  * @child: (out): return location for a #ClutterActor
17108  *
17109  * Advances the @iter and retrieves the previous child of the root
17110  * #ClutterActor that was used to initialize the #ClutterActorIterator.
17111  *
17112  * If the iterator can advance, this function returns %TRUE and sets the
17113  * @child argument.
17114  *
17115  * If the iterator cannot advance, this function returns %FALSE, and
17116  * the contents of @child are undefined.
17117  *
17118  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
17119  *
17120  * Since: 1.10
17121  */
17122 gboolean
17123 clutter_actor_iter_prev (ClutterActorIter  *iter,
17124                          ClutterActor     **child)
17125 {
17126   RealActorIter *ri = (RealActorIter *) iter;
17127
17128   g_return_val_if_fail (iter != NULL, FALSE);
17129   g_return_val_if_fail (ri->root != NULL, FALSE);
17130 #ifndef G_DISABLE_ASSERT
17131   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
17132 #endif
17133
17134   if (ri->current == NULL)
17135     ri->current = ri->root->priv->last_child;
17136   else
17137     ri->current = ri->current->priv->prev_sibling;
17138
17139   if (child != NULL)
17140     *child = ri->current;
17141
17142   return ri->current != NULL;
17143 }
17144
17145 /**
17146  * clutter_actor_iter_remove:
17147  * @iter: a #ClutterActorIter
17148  *
17149  * Safely removes the #ClutterActor currently pointer to by the iterator
17150  * from its parent.
17151  *
17152  * This function can only be called after clutter_actor_iter_next() or
17153  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17154  * than once for the same actor.
17155  *
17156  * This function will call clutter_actor_remove_child() internally.
17157  *
17158  * Since: 1.10
17159  */
17160 void
17161 clutter_actor_iter_remove (ClutterActorIter *iter)
17162 {
17163   RealActorIter *ri = (RealActorIter *) iter;
17164   ClutterActor *cur;
17165
17166   g_return_if_fail (iter != NULL);
17167   g_return_if_fail (ri->root != NULL);
17168 #ifndef G_DISABLE_ASSERT
17169   g_return_if_fail (ri->age == ri->root->priv->age);
17170 #endif
17171   g_return_if_fail (ri->current != NULL);
17172
17173   cur = ri->current;
17174
17175   if (cur != NULL)
17176     {
17177       ri->current = cur->priv->prev_sibling;
17178
17179       clutter_actor_remove_child_internal (ri->root, cur,
17180                                            REMOVE_CHILD_DEFAULT_FLAGS);
17181
17182       ri->age += 1;
17183     }
17184 }
17185
17186 /**
17187  * clutter_actor_iter_destroy:
17188  * @iter: a #ClutterActorIter
17189  *
17190  * Safely destroys the #ClutterActor currently pointer to by the iterator
17191  * from its parent.
17192  *
17193  * This function can only be called after clutter_actor_iter_next() or
17194  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
17195  * than once for the same actor.
17196  *
17197  * This function will call clutter_actor_destroy() internally.
17198  *
17199  * Since: 1.10
17200  */
17201 void
17202 clutter_actor_iter_destroy (ClutterActorIter *iter)
17203 {
17204   RealActorIter *ri = (RealActorIter *) iter;
17205   ClutterActor *cur;
17206
17207   g_return_if_fail (iter != NULL);
17208   g_return_if_fail (ri->root != NULL);
17209 #ifndef G_DISABLE_ASSERT
17210   g_return_if_fail (ri->age == ri->root->priv->age);
17211 #endif
17212   g_return_if_fail (ri->current != NULL);
17213
17214   cur = ri->current;
17215
17216   if (cur != NULL)
17217     {
17218       ri->current = cur->priv->prev_sibling;
17219
17220       clutter_actor_destroy (cur);
17221
17222       ri->age += 1;
17223     }
17224 }
17225
17226 static const ClutterAnimationInfo default_animation_info = {
17227   NULL,         /* transitions */
17228   NULL,         /* states */
17229   NULL,         /* cur_state */
17230 };
17231
17232 static void
17233 clutter_animation_info_free (gpointer data)
17234 {
17235   if (data != NULL)
17236     {
17237       ClutterAnimationInfo *info = data;
17238
17239       if (info->transitions != NULL)
17240         g_hash_table_unref (info->transitions);
17241
17242       if (info->states != NULL)
17243         g_array_unref (info->states);
17244
17245       g_slice_free (ClutterAnimationInfo, info);
17246     }
17247 }
17248
17249 const ClutterAnimationInfo *
17250 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
17251 {
17252   const ClutterAnimationInfo *res;
17253   GObject *obj = G_OBJECT (self);
17254
17255   res = g_object_get_qdata (obj, quark_actor_animation_info);
17256   if (res != NULL)
17257     return res;
17258
17259   return &default_animation_info;
17260 }
17261
17262 ClutterAnimationInfo *
17263 _clutter_actor_get_animation_info (ClutterActor *self)
17264 {
17265   GObject *obj = G_OBJECT (self);
17266   ClutterAnimationInfo *res;
17267
17268   res = g_object_get_qdata (obj, quark_actor_animation_info);
17269   if (res == NULL)
17270     {
17271       res = g_slice_new (ClutterAnimationInfo);
17272
17273       *res = default_animation_info;
17274
17275       g_object_set_qdata_full (obj, quark_actor_animation_info,
17276                                res,
17277                                clutter_animation_info_free);
17278     }
17279
17280   return res;
17281 }
17282
17283 ClutterTransition *
17284 _clutter_actor_get_transition (ClutterActor *actor,
17285                                GParamSpec   *pspec)
17286 {
17287   const ClutterAnimationInfo *info;
17288
17289   info = _clutter_actor_get_animation_info_or_defaults (actor);
17290
17291   if (info->transitions == NULL)
17292     return NULL;
17293
17294   return g_hash_table_lookup (info->transitions, pspec->name);
17295 }
17296
17297 static void
17298 transition_closure_free (gpointer data)
17299 {
17300   if (G_LIKELY (data != NULL))
17301     {
17302       TransitionClosure *clos = data;
17303       ClutterTimeline *timeline;
17304
17305       timeline = CLUTTER_TIMELINE (clos->transition);
17306
17307       if (clutter_timeline_is_playing (timeline))
17308         clutter_timeline_stop (timeline);
17309
17310       g_signal_handler_disconnect (clos->transition, clos->completed_id);
17311
17312       g_object_unref (clos->transition);
17313       g_free (clos->name);
17314
17315       g_slice_free (TransitionClosure, clos);
17316     }
17317 }
17318
17319 static void
17320 on_transition_stopped (ClutterTransition *transition,
17321                        gboolean           is_finished,
17322                        TransitionClosure *clos)
17323 {
17324   ClutterActor *actor = clos->actor;
17325   ClutterAnimationInfo *info;
17326
17327   /* reset the caches used by animations */
17328   clutter_actor_store_content_box (actor, NULL);
17329
17330   if (!is_finished)
17331     return;
17332
17333   info = _clutter_actor_get_animation_info (actor);
17334
17335   /* we take a reference here because removing the closure
17336    * will release the reference on the transition, and we
17337    * want the transition to survive the signal emission;
17338    * the master clock will release the last reference at
17339    * the end of the frame processing.
17340    */
17341   g_object_ref (transition);
17342   g_hash_table_remove (info->transitions, clos->name);
17343
17344   /* if it's the last transition then we clean up */
17345   if (g_hash_table_size (info->transitions) == 0)
17346     {
17347       g_hash_table_unref (info->transitions);
17348       info->transitions = NULL;
17349
17350       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17351                     _clutter_actor_get_debug_name (actor));
17352
17353       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17354     }
17355 }
17356
17357 void
17358 _clutter_actor_update_transition (ClutterActor *actor,
17359                                   GParamSpec   *pspec,
17360                                   ...)
17361 {
17362   TransitionClosure *clos;
17363   ClutterTimeline *timeline;
17364   ClutterInterval *interval;
17365   const ClutterAnimationInfo *info;
17366   va_list var_args;
17367   GType ptype;
17368   GValue initial = G_VALUE_INIT;
17369   GValue final = G_VALUE_INIT;
17370   char *error = NULL;
17371
17372   info = _clutter_actor_get_animation_info_or_defaults (actor);
17373
17374   if (info->transitions == NULL)
17375     return;
17376
17377   clos = g_hash_table_lookup (info->transitions, pspec->name);
17378   if (clos == NULL)
17379     return;
17380
17381   timeline = CLUTTER_TIMELINE (clos->transition);
17382
17383   va_start (var_args, pspec);
17384
17385   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17386
17387   g_value_init (&initial, ptype);
17388   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17389                                         pspec->name,
17390                                         &initial);
17391
17392   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17393   if (error != NULL)
17394     {
17395       g_critical ("%s: %s", G_STRLOC, error);
17396       g_free (error);
17397       goto out;
17398     }
17399
17400   interval = clutter_transition_get_interval (clos->transition);
17401   clutter_interval_set_initial_value (interval, &initial);
17402   clutter_interval_set_final_value (interval, &final);
17403
17404   /* if we're updating with an easing duration of zero milliseconds,
17405    * we just jump the timeline to the end and let it run its course
17406    */
17407   if (info->cur_state != NULL &&
17408       info->cur_state->easing_duration != 0)
17409     {
17410       guint cur_duration = clutter_timeline_get_duration (timeline);
17411       ClutterAnimationMode cur_mode =
17412         clutter_timeline_get_progress_mode (timeline);
17413
17414       if (cur_duration != info->cur_state->easing_duration)
17415         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17416
17417       if (cur_mode != info->cur_state->easing_mode)
17418         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17419
17420       clutter_timeline_rewind (timeline);
17421     }
17422   else
17423     {
17424       guint duration = clutter_timeline_get_duration (timeline);
17425
17426       clutter_timeline_advance (timeline, duration);
17427     }
17428
17429 out:
17430   g_value_unset (&initial);
17431   g_value_unset (&final);
17432
17433   va_end (var_args);
17434 }
17435
17436 /*< private >*
17437  * _clutter_actor_create_transition:
17438  * @actor: a #ClutterActor
17439  * @pspec: the property used for the transition
17440  * @...: initial and final state
17441  *
17442  * Creates a #ClutterTransition for the property represented by @pspec.
17443  *
17444  * Return value: a #ClutterTransition
17445  */
17446 ClutterTransition *
17447 _clutter_actor_create_transition (ClutterActor *actor,
17448                                   GParamSpec   *pspec,
17449                                   ...)
17450 {
17451   ClutterAnimationInfo *info;
17452   ClutterTransition *res = NULL;
17453   gboolean call_restore = FALSE;
17454   TransitionClosure *clos;
17455   va_list var_args;
17456
17457   info = _clutter_actor_get_animation_info (actor);
17458
17459   /* XXX - this will go away in 2.0
17460    *
17461    * if no state has been pushed, we assume that the easing state is
17462    * in "compatibility mode": all transitions have a duration of 0
17463    * msecs, which means that they happen immediately. in Clutter 2.0
17464    * this will turn into a g_assert(info->states != NULL), as every
17465    * actor will start with a predefined easing state
17466    */
17467   if (info->states == NULL)
17468     {
17469       clutter_actor_save_easing_state (actor);
17470       clutter_actor_set_easing_duration (actor, 0);
17471       call_restore = TRUE;
17472     }
17473
17474   if (info->transitions == NULL)
17475     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17476                                                NULL,
17477                                                transition_closure_free);
17478
17479   va_start (var_args, pspec);
17480
17481   clos = g_hash_table_lookup (info->transitions, pspec->name);
17482   if (clos == NULL)
17483     {
17484       ClutterTimeline *timeline;
17485       ClutterInterval *interval;
17486       GValue initial = G_VALUE_INIT;
17487       GValue final = G_VALUE_INIT;
17488       GType ptype;
17489       char *error;
17490
17491       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17492
17493       G_VALUE_COLLECT_INIT (&initial, ptype,
17494                             var_args, 0,
17495                             &error);
17496       if (error != NULL)
17497         {
17498           g_critical ("%s: %s", G_STRLOC, error);
17499           g_free (error);
17500           goto out;
17501         }
17502
17503       G_VALUE_COLLECT_INIT (&final, ptype,
17504                             var_args, 0,
17505                             &error);
17506
17507       if (error != NULL)
17508         {
17509           g_critical ("%s: %s", G_STRLOC, error);
17510           g_value_unset (&initial);
17511           g_free (error);
17512           goto out;
17513         }
17514
17515       /* if the current easing state has a duration of 0, then we don't
17516        * bother to create the transition, and we just set the final value
17517        * directly on the actor; we don't go through the Animatable
17518        * interface because we know we got here through an animatable
17519        * property.
17520        */
17521       if (info->cur_state->easing_duration == 0)
17522         {
17523           clutter_actor_set_animatable_property (actor,
17524                                                  pspec->param_id,
17525                                                  &final,
17526                                                  pspec);
17527           g_value_unset (&initial);
17528           g_value_unset (&final);
17529
17530           goto out;
17531         }
17532
17533       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17534
17535       g_value_unset (&initial);
17536       g_value_unset (&final);
17537
17538       res = clutter_property_transition_new (pspec->name);
17539
17540       clutter_transition_set_interval (res, interval);
17541       clutter_transition_set_remove_on_complete (res, TRUE);
17542
17543       timeline = CLUTTER_TIMELINE (res);
17544       clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17545       clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17546       clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17547
17548       CLUTTER_NOTE (ANIMATION,
17549                     "Created transition for %s:%s (len:%u, mode:%s, delay:%u)",
17550                     _clutter_actor_get_debug_name (actor),
17551                     pspec->name,
17552                     info->cur_state->easing_duration,
17553                     clutter_get_easing_name_for_mode (info->cur_state->easing_mode),
17554                     info->cur_state->easing_delay);
17555
17556       /* this will start the transition as well */
17557       clutter_actor_add_transition (actor, pspec->name, res);
17558
17559       /* the actor now owns the transition */
17560       g_object_unref (res);
17561     }
17562   else
17563     res = clos->transition;
17564
17565 out:
17566   if (call_restore)
17567     clutter_actor_restore_easing_state (actor);
17568
17569   va_end (var_args);
17570
17571   return res;
17572 }
17573
17574 /**
17575  * clutter_actor_add_transition:
17576  * @self: a #ClutterActor
17577  * @name: the name of the transition to add
17578  * @transition: the #ClutterTransition to add
17579  *
17580  * Adds a @transition to the #ClutterActor's list of animations.
17581  *
17582  * The @name string is a per-actor unique identifier of the @transition: only
17583  * one #ClutterTransition can be associated to the specified @name.
17584  *
17585  * The @transition will be started once added.
17586  *
17587  * This function will take a reference on the @transition.
17588  *
17589  * This function is usually called implicitly when modifying an animatable
17590  * property.
17591  *
17592  * Since: 1.10
17593  */
17594 void
17595 clutter_actor_add_transition (ClutterActor      *self,
17596                               const char        *name,
17597                               ClutterTransition *transition)
17598 {
17599   ClutterTimeline *timeline;
17600   TransitionClosure *clos;
17601   ClutterAnimationInfo *info;
17602
17603   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17604   g_return_if_fail (name != NULL);
17605   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17606
17607   info = _clutter_actor_get_animation_info (self);
17608
17609   if (info->transitions == NULL)
17610     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17611                                                NULL,
17612                                                transition_closure_free);
17613
17614   if (g_hash_table_lookup (info->transitions, name) != NULL)
17615     {
17616       g_warning ("A transition with name '%s' already exists for "
17617                  "the actor '%s'",
17618                  name,
17619                  _clutter_actor_get_debug_name (self));
17620       return;
17621     }
17622
17623   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17624
17625   timeline = CLUTTER_TIMELINE (transition);
17626
17627   clos = g_slice_new (TransitionClosure);
17628   clos->actor = self;
17629   clos->transition = g_object_ref (transition);
17630   clos->name = g_strdup (name);
17631   clos->completed_id = g_signal_connect (timeline, "stopped",
17632                                          G_CALLBACK (on_transition_stopped),
17633                                          clos);
17634
17635   CLUTTER_NOTE (ANIMATION,
17636                 "Adding transition '%s' [%p] to actor '%s'",
17637                 clos->name,
17638                 clos->transition,
17639                 _clutter_actor_get_debug_name (self));
17640
17641   g_hash_table_insert (info->transitions, clos->name, clos);
17642   clutter_timeline_start (timeline);
17643 }
17644
17645 /**
17646  * clutter_actor_remove_transition:
17647  * @self: a #ClutterActor
17648  * @name: the name of the transition to remove
17649  *
17650  * Removes the transition stored inside a #ClutterActor using @name
17651  * identifier.
17652  *
17653  * If the transition is currently in progress, it will be stopped.
17654  *
17655  * This function releases the reference acquired when the transition
17656  * was added to the #ClutterActor.
17657  *
17658  * Since: 1.10
17659  */
17660 void
17661 clutter_actor_remove_transition (ClutterActor *self,
17662                                  const char   *name)
17663 {
17664   const ClutterAnimationInfo *info;
17665
17666   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17667   g_return_if_fail (name != NULL);
17668
17669   info = _clutter_actor_get_animation_info_or_defaults (self);
17670
17671   if (info->transitions == NULL)
17672     return;
17673
17674   g_hash_table_remove (info->transitions, name);
17675 }
17676
17677 /**
17678  * clutter_actor_remove_all_transitions:
17679  * @self: a #ClutterActor
17680  *
17681  * Removes all transitions associated to @self.
17682  *
17683  * Since: 1.10
17684  */
17685 void
17686 clutter_actor_remove_all_transitions (ClutterActor *self)
17687 {
17688   const ClutterAnimationInfo *info;
17689
17690   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17691
17692   info = _clutter_actor_get_animation_info_or_defaults (self);
17693   if (info->transitions == NULL)
17694     return;
17695
17696   g_hash_table_remove_all (info->transitions);
17697 }
17698
17699 /**
17700  * clutter_actor_set_easing_duration:
17701  * @self: a #ClutterActor
17702  * @msecs: the duration of the easing, or %NULL
17703  *
17704  * Sets the duration of the tweening for animatable properties
17705  * of @self for the current easing state.
17706  *
17707  * Since: 1.10
17708  */
17709 void
17710 clutter_actor_set_easing_duration (ClutterActor *self,
17711                                    guint         msecs)
17712 {
17713   ClutterAnimationInfo *info;
17714
17715   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17716
17717   info = _clutter_actor_get_animation_info (self);
17718
17719   if (info->cur_state == NULL)
17720     {
17721       g_warning ("You must call clutter_actor_save_easing_state() prior "
17722                  "to calling clutter_actor_set_easing_duration().");
17723       return;
17724     }
17725
17726   if (info->cur_state->easing_duration != msecs)
17727     info->cur_state->easing_duration = msecs;
17728 }
17729
17730 /**
17731  * clutter_actor_get_easing_duration:
17732  * @self: a #ClutterActor
17733  *
17734  * Retrieves the duration of the tweening for animatable
17735  * properties of @self for the current easing state.
17736  *
17737  * Return value: the duration of the tweening, in milliseconds
17738  *
17739  * Since: 1.10
17740  */
17741 guint
17742 clutter_actor_get_easing_duration (ClutterActor *self)
17743 {
17744   const ClutterAnimationInfo *info;
17745
17746   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17747
17748   info = _clutter_actor_get_animation_info_or_defaults (self);
17749
17750   if (info->cur_state != NULL)
17751     return info->cur_state->easing_duration;
17752
17753   return 0;
17754 }
17755
17756 /**
17757  * clutter_actor_set_easing_mode:
17758  * @self: a #ClutterActor
17759  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17760  *
17761  * Sets the easing mode for the tweening of animatable properties
17762  * of @self.
17763  *
17764  * Since: 1.10
17765  */
17766 void
17767 clutter_actor_set_easing_mode (ClutterActor         *self,
17768                                ClutterAnimationMode  mode)
17769 {
17770   ClutterAnimationInfo *info;
17771
17772   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17773   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17774   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17775
17776   info = _clutter_actor_get_animation_info (self);
17777
17778   if (info->cur_state == NULL)
17779     {
17780       g_warning ("You must call clutter_actor_save_easing_state() prior "
17781                  "to calling clutter_actor_set_easing_mode().");
17782       return;
17783     }
17784
17785   if (info->cur_state->easing_mode != mode)
17786     info->cur_state->easing_mode = mode;
17787 }
17788
17789 /**
17790  * clutter_actor_get_easing_mode:
17791  * @self: a #ClutterActor
17792  *
17793  * Retrieves the easing mode for the tweening of animatable properties
17794  * of @self for the current easing state.
17795  *
17796  * Return value: an easing mode
17797  *
17798  * Since: 1.10
17799  */
17800 ClutterAnimationMode
17801 clutter_actor_get_easing_mode (ClutterActor *self)
17802 {
17803   const ClutterAnimationInfo *info;
17804
17805   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17806
17807   info = _clutter_actor_get_animation_info_or_defaults (self);
17808
17809   if (info->cur_state != NULL)
17810     return info->cur_state->easing_mode;
17811
17812   return CLUTTER_EASE_OUT_CUBIC;
17813 }
17814
17815 /**
17816  * clutter_actor_set_easing_delay:
17817  * @self: a #ClutterActor
17818  * @msecs: the delay before the start of the tweening, in milliseconds
17819  *
17820  * Sets the delay that should be applied before tweening animatable
17821  * properties.
17822  *
17823  * Since: 1.10
17824  */
17825 void
17826 clutter_actor_set_easing_delay (ClutterActor *self,
17827                                 guint         msecs)
17828 {
17829   ClutterAnimationInfo *info;
17830
17831   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17832
17833   info = _clutter_actor_get_animation_info (self);
17834
17835   if (info->cur_state == NULL)
17836     {
17837       g_warning ("You must call clutter_actor_save_easing_state() prior "
17838                  "to calling clutter_actor_set_easing_delay().");
17839       return;
17840     }
17841
17842   if (info->cur_state->easing_delay != msecs)
17843     info->cur_state->easing_delay = msecs;
17844 }
17845
17846 /**
17847  * clutter_actor_get_easing_delay:
17848  * @self: a #ClutterActor
17849  *
17850  * Retrieves the delay that should be applied when tweening animatable
17851  * properties.
17852  *
17853  * Return value: a delay, in milliseconds
17854  *
17855  * Since: 1.10
17856  */
17857 guint
17858 clutter_actor_get_easing_delay (ClutterActor *self)
17859 {
17860   const ClutterAnimationInfo *info;
17861
17862   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17863
17864   info = _clutter_actor_get_animation_info_or_defaults (self);
17865
17866   if (info->cur_state != NULL)
17867     return info->cur_state->easing_delay;
17868
17869   return 0;
17870 }
17871
17872 /**
17873  * clutter_actor_get_transition:
17874  * @self: a #ClutterActor
17875  * @name: the name of the transition
17876  *
17877  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17878  * transition @name.
17879  *
17880  * Transitions created for animatable properties use the name of the
17881  * property itself, for instance the code below:
17882  *
17883  * |[
17884  *   clutter_actor_set_easing_duration (actor, 1000);
17885  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17886  *
17887  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17888  *   g_signal_connect (transition, "stopped",
17889  *                     G_CALLBACK (on_transition_stopped),
17890  *                     actor);
17891  * ]|
17892  *
17893  * will call the <function>on_transition_stopped</function> callback when
17894  * the transition is finished.
17895  *
17896  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17897  *   was found to match the passed name; the returned instance is owned
17898  *   by Clutter and it should not be freed
17899  *
17900  * Since: 1.10
17901  */
17902 ClutterTransition *
17903 clutter_actor_get_transition (ClutterActor *self,
17904                               const char   *name)
17905 {
17906   TransitionClosure *clos;
17907   const ClutterAnimationInfo *info;
17908
17909   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17910   g_return_val_if_fail (name != NULL, NULL);
17911
17912   info = _clutter_actor_get_animation_info_or_defaults (self);
17913   if (info->transitions == NULL)
17914     return NULL;
17915
17916   clos = g_hash_table_lookup (info->transitions, name);
17917   if (clos == NULL)
17918     return NULL;
17919
17920   return clos->transition;
17921 }
17922
17923 /**
17924  * clutter_actor_save_easing_state:
17925  * @self: a #ClutterActor
17926  *
17927  * Saves the current easing state for animatable properties, and creates
17928  * a new state with the default values for easing mode and duration.
17929  *
17930  * Since: 1.10
17931  */
17932 void
17933 clutter_actor_save_easing_state (ClutterActor *self)
17934 {
17935   ClutterAnimationInfo *info;
17936   AState new_state;
17937
17938   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17939
17940   info = _clutter_actor_get_animation_info (self);
17941
17942   if (info->states == NULL)
17943     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17944
17945   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17946   new_state.easing_duration = 250;
17947   new_state.easing_delay = 0;
17948
17949   g_array_append_val (info->states, new_state);
17950
17951   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17952 }
17953
17954 /**
17955  * clutter_actor_restore_easing_state:
17956  * @self: a #ClutterActor
17957  *
17958  * Restores the easing state as it was prior to a call to
17959  * clutter_actor_save_easing_state().
17960  *
17961  * Since: 1.10
17962  */
17963 void
17964 clutter_actor_restore_easing_state (ClutterActor *self)
17965 {
17966   ClutterAnimationInfo *info;
17967
17968   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17969
17970   info = _clutter_actor_get_animation_info (self);
17971
17972   if (info->states == NULL)
17973     {
17974       g_critical ("The function clutter_actor_restore_easing_state() has "
17975                   "called without a previous call to "
17976                   "clutter_actor_save_easing_state().");
17977       return;
17978     }
17979
17980   g_array_remove_index (info->states, info->states->len - 1);
17981
17982   if (info->states->len > 0)
17983     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17984   else
17985     {
17986       g_array_unref (info->states);
17987       info->states = NULL;
17988       info->cur_state = NULL;
17989     }
17990 }
17991
17992 /**
17993  * clutter_actor_set_content:
17994  * @self: a #ClutterActor
17995  * @content: (allow-none): a #ClutterContent, or %NULL
17996  *
17997  * Sets the contents of a #ClutterActor.
17998  *
17999  * Since: 1.10
18000  */
18001 void
18002 clutter_actor_set_content (ClutterActor   *self,
18003                            ClutterContent *content)
18004 {
18005   ClutterActorPrivate *priv;
18006
18007   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18008   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
18009
18010   priv = self->priv;
18011
18012   if (priv->content != NULL)
18013     {
18014       _clutter_content_detached (priv->content, self);
18015       g_clear_object (&priv->content);
18016     }
18017
18018   priv->content = content;
18019
18020   if (priv->content != NULL)
18021     {
18022       g_object_ref (priv->content);
18023       _clutter_content_attached (priv->content, self);
18024     }
18025
18026   /* given that the content is always painted within the allocation,
18027    * we only need to queue a redraw here
18028    */
18029   clutter_actor_queue_redraw (self);
18030
18031   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
18032
18033   /* if the content gravity is not resize-fill, and the new content has a
18034    * different preferred size than the previous one, then the content box
18035    * may have been changed. since we compute that lazily, we just notify
18036    * here, and let whomever watches :content-box do whatever they need to
18037    * do.
18038    */
18039   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18040     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
18041 }
18042
18043 /**
18044  * clutter_actor_get_content:
18045  * @self: a #ClutterActor
18046  *
18047  * Retrieves the contents of @self.
18048  *
18049  * Return value: (transfer none): a pointer to the #ClutterContent instance,
18050  *   or %NULL if none was set
18051  *
18052  * Since: 1.10
18053  */
18054 ClutterContent *
18055 clutter_actor_get_content (ClutterActor *self)
18056 {
18057   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
18058
18059   return self->priv->content;
18060 }
18061
18062 /**
18063  * clutter_actor_set_content_gravity:
18064  * @self: a #ClutterActor
18065  * @gravity: the #ClutterContentGravity
18066  *
18067  * Sets the gravity of the #ClutterContent used by @self.
18068  *
18069  * See the description of the #ClutterActor:content-gravity property for
18070  * more information.
18071  *
18072  * The #ClutterActor:content-gravity property is animatable.
18073  *
18074  * Since: 1.10
18075  */
18076 void
18077 clutter_actor_set_content_gravity (ClutterActor *self,
18078                                    ClutterContentGravity  gravity)
18079 {
18080   ClutterActorPrivate *priv;
18081
18082   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18083
18084   priv = self->priv;
18085
18086   if (priv->content_gravity == gravity)
18087     return;
18088
18089   priv->content_box_valid = FALSE;
18090
18091   if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
18092     {
18093       ClutterActorBox from_box, to_box;
18094
18095       clutter_actor_get_content_box (self, &from_box);
18096
18097       priv->content_gravity = gravity;
18098
18099       clutter_actor_get_content_box (self, &to_box);
18100
18101       _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
18102                                         &from_box,
18103                                         &to_box);
18104     }
18105   else
18106     {
18107       ClutterActorBox to_box;
18108
18109       priv->content_gravity = gravity;
18110
18111       clutter_actor_get_content_box (self, &to_box);
18112
18113       _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
18114                                         &to_box);
18115     }
18116
18117   clutter_actor_queue_redraw (self);
18118
18119   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
18120 }
18121
18122 /**
18123  * clutter_actor_get_content_gravity:
18124  * @self: a #ClutterActor
18125  *
18126  * Retrieves the content gravity as set using
18127  * clutter_actor_get_content_gravity().
18128  *
18129  * Return value: the content gravity
18130  *
18131  * Since: 1.10
18132  */
18133 ClutterContentGravity
18134 clutter_actor_get_content_gravity (ClutterActor *self)
18135 {
18136   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
18137                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
18138
18139   return self->priv->content_gravity;
18140 }
18141
18142 /**
18143  * clutter_actor_get_content_box:
18144  * @self: a #ClutterActor
18145  * @box: (out caller-allocates): the return location for the bounding
18146  *   box for the #ClutterContent
18147  *
18148  * Retrieves the bounding box for the #ClutterContent of @self.
18149  *
18150  * The bounding box is relative to the actor's allocation.
18151  *
18152  * If no #ClutterContent is set for @self, or if @self has not been
18153  * allocated yet, then the result is undefined.
18154  *
18155  * The content box is guaranteed to be, at most, as big as the allocation
18156  * of the #ClutterActor.
18157  *
18158  * If the #ClutterContent used by the actor has a preferred size, then
18159  * it is possible to modify the content box by using the
18160  * #ClutterActor:content-gravity property.
18161  *
18162  * Since: 1.10
18163  */
18164 void
18165 clutter_actor_get_content_box (ClutterActor    *self,
18166                                ClutterActorBox *box)
18167 {
18168   ClutterActorPrivate *priv;
18169   gfloat content_w, content_h;
18170   gfloat alloc_w, alloc_h;
18171
18172   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18173   g_return_if_fail (box != NULL);
18174
18175   priv = self->priv;
18176
18177   box->x1 = 0.f;
18178   box->y1 = 0.f;
18179   box->x2 = priv->allocation.x2 - priv->allocation.x1;
18180   box->y2 = priv->allocation.y2 - priv->allocation.y1;
18181
18182   if (priv->content_box_valid)
18183     {
18184       *box = priv->content_box;
18185       return;
18186     }
18187
18188   /* no need to do any more work */
18189   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
18190     return;
18191
18192   if (priv->content == NULL)
18193     return;
18194
18195   /* if the content does not have a preferred size then there is
18196    * no point in computing the content box
18197    */
18198   if (!clutter_content_get_preferred_size (priv->content,
18199                                            &content_w,
18200                                            &content_h))
18201     return;
18202
18203   alloc_w = box->x2;
18204   alloc_h = box->y2;
18205
18206   switch (priv->content_gravity)
18207     {
18208     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
18209       box->x2 = box->x1 + MIN (content_w, alloc_w);
18210       box->y2 = box->y1 + MIN (content_h, alloc_h);
18211       break;
18212
18213     case CLUTTER_CONTENT_GRAVITY_TOP:
18214       if (alloc_w > content_w)
18215         {
18216           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18217           box->x2 = box->x1 + content_w;
18218         }
18219       box->y2 = box->y1 + MIN (content_h, alloc_h);
18220       break;
18221
18222     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
18223       if (alloc_w > content_w)
18224         {
18225           box->x1 += (alloc_w - content_w);
18226           box->x2 = box->x1 + content_w;
18227         }
18228       box->y2 = box->y1 + MIN (content_h, alloc_h);
18229       break;
18230
18231     case CLUTTER_CONTENT_GRAVITY_LEFT:
18232       box->x2 = box->x1 + MIN (content_w, alloc_w);
18233       if (alloc_h > content_h)
18234         {
18235           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18236           box->y2 = box->y1 + content_h;
18237         }
18238       break;
18239
18240     case CLUTTER_CONTENT_GRAVITY_CENTER:
18241       if (alloc_w > content_w)
18242         {
18243           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18244           box->x2 = box->x1 + content_w;
18245         }
18246       if (alloc_h > content_h)
18247         {
18248           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18249           box->y2 = box->y1 + content_h;
18250         }
18251       break;
18252
18253     case CLUTTER_CONTENT_GRAVITY_RIGHT:
18254       if (alloc_w > content_w)
18255         {
18256           box->x1 += (alloc_w - content_w);
18257           box->x2 = box->x1 + content_w;
18258         }
18259       if (alloc_h > content_h)
18260         {
18261           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18262           box->y2 = box->y1 + content_h;
18263         }
18264       break;
18265
18266     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18267       box->x2 = box->x1 + MIN (content_w, alloc_w);
18268       if (alloc_h > content_h)
18269         {
18270           box->y1 += (alloc_h - content_h);
18271           box->y2 = box->y1 + content_h;
18272         }
18273       break;
18274
18275     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18276       if (alloc_w > content_w)
18277         {
18278           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18279           box->x2 = box->x1 + content_w;
18280         }
18281       if (alloc_h > content_h)
18282         {
18283           box->y1 += (alloc_h - content_h);
18284           box->y2 = box->y1 + content_h;
18285         }
18286       break;
18287
18288     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18289       if (alloc_w > content_w)
18290         {
18291           box->x1 += (alloc_w - content_w);
18292           box->x2 = box->x1 + content_w;
18293         }
18294       if (alloc_h > content_h)
18295         {
18296           box->y1 += (alloc_h - content_h);
18297           box->y2 = box->y1 + content_h;
18298         }
18299       break;
18300
18301     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18302       g_assert_not_reached ();
18303       break;
18304
18305     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18306       {
18307         double r_c = content_w / content_h;
18308
18309         if (r_c >= 1.0)
18310           {
18311             if ((alloc_w / r_c) > alloc_h)
18312               {
18313                 box->x1 = 0.f;
18314                 box->x2 = alloc_w;
18315
18316                 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18317                 box->y2 = box->y1 + (alloc_w / r_c);
18318               }
18319             else
18320               {
18321                 box->y1 = 0.f;
18322                 box->y2 = alloc_h;
18323
18324                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18325                 box->x2 = box->x1 + (alloc_h * r_c);
18326               }
18327           }
18328         else
18329           {
18330             if ((alloc_w / r_c) > alloc_h)
18331               {
18332                 box->y1 = 0.f;
18333                 box->y2 = alloc_h;
18334
18335                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18336                 box->x2 = box->x1 + (alloc_h * r_c);
18337               }
18338             else
18339               {
18340                 box->x1 = 0.f;
18341                 box->x2 = alloc_w;
18342
18343                 box->y1 = (alloc_h - (alloc_w / r_c)) / 2.0f;
18344                 box->y2 = box->y1 + (alloc_w / r_c);
18345               }
18346           }
18347
18348         CLUTTER_NOTE (LAYOUT,
18349                       "r_c: %.3f, r_a: %.3f\t"
18350                       "a: [%.2fx%.2f], c: [%.2fx%.2f]\t"
18351                       "b: [%.2f, %.2f, %.2f, %.2f]",
18352                       r_c, alloc_w / alloc_h,
18353                       alloc_w, alloc_h,
18354                       content_w, content_h,
18355                       box->x1, box->y1, box->x2, box->y2);
18356       }
18357       break;
18358     }
18359 }
18360
18361 /**
18362  * clutter_actor_set_content_scaling_filters:
18363  * @self: a #ClutterActor
18364  * @min_filter: the minification filter for the content
18365  * @mag_filter: the magnification filter for the content
18366  *
18367  * Sets the minification and magnification filter to be applied when
18368  * scaling the #ClutterActor:content of a #ClutterActor.
18369  *
18370  * The #ClutterActor:minification-filter will be used when reducing
18371  * the size of the content; the #ClutterActor:magnification-filter
18372  * will be used when increasing the size of the content.
18373  *
18374  * Since: 1.10
18375  */
18376 void
18377 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18378                                            ClutterScalingFilter  min_filter,
18379                                            ClutterScalingFilter  mag_filter)
18380 {
18381   ClutterActorPrivate *priv;
18382   gboolean changed;
18383   GObject *obj;
18384
18385   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18386
18387   priv = self->priv;
18388   obj = G_OBJECT (self);
18389
18390   g_object_freeze_notify (obj);
18391
18392   changed = FALSE;
18393
18394   if (priv->min_filter != min_filter)
18395     {
18396       priv->min_filter = min_filter;
18397       changed = TRUE;
18398
18399       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18400     }
18401
18402   if (priv->mag_filter != mag_filter)
18403     {
18404       priv->mag_filter = mag_filter;
18405       changed = TRUE;
18406
18407       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18408     }
18409
18410   if (changed)
18411     clutter_actor_queue_redraw (self);
18412
18413   g_object_thaw_notify (obj);
18414 }
18415
18416 /**
18417  * clutter_actor_get_content_scaling_filters:
18418  * @self: a #ClutterActor
18419  * @min_filter: (out) (allow-none): return location for the minification
18420  *   filter, or %NULL
18421  * @mag_filter: (out) (allow-none): return location for the magnification
18422  *   filter, or %NULL
18423  *
18424  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18425  *
18426  * Since: 1.10
18427  */
18428 void
18429 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18430                                            ClutterScalingFilter *min_filter,
18431                                            ClutterScalingFilter *mag_filter)
18432 {
18433   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18434
18435   if (min_filter != NULL)
18436     *min_filter = self->priv->min_filter;
18437
18438   if (mag_filter != NULL)
18439     *mag_filter = self->priv->mag_filter;
18440 }
18441
18442 /*
18443  * clutter_actor_queue_compute_expand:
18444  * @self: a #ClutterActor
18445  *
18446  * Invalidates the needs_x_expand and needs_y_expand flags on @self
18447  * and its parents up to the top-level actor.
18448  *
18449  * This function also queues a relayout if anything changed.
18450  */
18451 static inline void
18452 clutter_actor_queue_compute_expand (ClutterActor *self)
18453 {
18454   ClutterActor *parent;
18455   gboolean changed;
18456
18457   if (self->priv->needs_compute_expand)
18458     return;
18459
18460   changed = FALSE;
18461   parent = self;
18462   while (parent != NULL)
18463     {
18464       if (!parent->priv->needs_compute_expand)
18465         {
18466           parent->priv->needs_compute_expand = TRUE;
18467           changed = TRUE;
18468         }
18469
18470       parent = parent->priv->parent;
18471     }
18472
18473   if (changed)
18474     clutter_actor_queue_relayout (self);
18475 }
18476
18477 /**
18478  * clutter_actor_set_x_expand:
18479  * @self: a #ClutterActor
18480  * @expand: whether the actor should expand horizontally
18481  *
18482  * Sets whether a #ClutterActor should expand horizontally; this means
18483  * that layout manager should allocate extra space for the actor, if
18484  * possible.
18485  *
18486  * Setting an actor to expand will also make all its parent expand, so
18487  * that it's possible to build an actor tree and only set this flag on
18488  * its leaves and not on every single actor.
18489  *
18490  * Since: 1.12
18491  */
18492 void
18493 clutter_actor_set_x_expand (ClutterActor *self,
18494                             gboolean      expand)
18495 {
18496   ClutterLayoutInfo *info;
18497
18498   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18499
18500   expand = !!expand;
18501
18502   info = _clutter_actor_get_layout_info (self);
18503   if (info->x_expand != expand)
18504     {
18505       info->x_expand = expand;
18506
18507       self->priv->x_expand_set = TRUE;
18508
18509       clutter_actor_queue_compute_expand (self);
18510
18511       g_object_notify_by_pspec (G_OBJECT (self),
18512                                 obj_props[PROP_X_EXPAND]);
18513     }
18514 }
18515
18516 /**
18517  * clutter_actor_get_x_expand:
18518  * @self: a #ClutterActor
18519  *
18520  * Retrieves the value set with clutter_actor_set_x_expand().
18521  *
18522  * See also: clutter_actor_needs_expand()
18523  *
18524  * Return value: %TRUE if the actor has been set to expand
18525  *
18526  * Since: 1.12
18527  */
18528 gboolean
18529 clutter_actor_get_x_expand (ClutterActor *self)
18530 {
18531   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18532
18533   return _clutter_actor_get_layout_info_or_defaults (self)->x_expand;
18534 }
18535
18536 /**
18537  * clutter_actor_set_y_expand:
18538  * @self: a #ClutterActor
18539  * @expand: whether the actor should expand vertically
18540  *
18541  * Sets whether a #ClutterActor should expand horizontally; this means
18542  * that layout manager should allocate extra space for the actor, if
18543  * possible.
18544  *
18545  * Setting an actor to expand will also make all its parent expand, so
18546  * that it's possible to build an actor tree and only set this flag on
18547  * its leaves and not on every single actor.
18548  *
18549  * Since: 1.12
18550  */
18551 void
18552 clutter_actor_set_y_expand (ClutterActor *self,
18553                             gboolean      expand)
18554 {
18555   ClutterLayoutInfo *info;
18556
18557   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18558
18559   expand = !!expand;
18560
18561   info = _clutter_actor_get_layout_info (self);
18562   if (info->y_expand != expand)
18563     {
18564       info->y_expand = expand;
18565
18566       self->priv->y_expand_set = TRUE;
18567
18568       clutter_actor_queue_compute_expand (self);
18569
18570       g_object_notify_by_pspec (G_OBJECT (self),
18571                                 obj_props[PROP_Y_EXPAND]);
18572     }
18573 }
18574
18575 /**
18576  * clutter_actor_get_y_expand:
18577  * @self: a #ClutterActor
18578  *
18579  * Retrieves the value set with clutter_actor_set_y_expand().
18580  *
18581  * See also: clutter_actor_needs_expand()
18582  *
18583  * Return value: %TRUE if the actor has been set to expand
18584  *
18585  * Since: 1.12
18586  */
18587 gboolean
18588 clutter_actor_get_y_expand (ClutterActor *self)
18589 {
18590   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18591
18592   return _clutter_actor_get_layout_info_or_defaults (self)->y_expand;
18593 }
18594
18595 static void
18596 clutter_actor_compute_expand_recursive (ClutterActor *self,
18597                                         gboolean     *x_expand_p,
18598                                         gboolean     *y_expand_p)
18599 {
18600   ClutterActorIter iter;
18601   ClutterActor *child;
18602   gboolean x_expand, y_expand;
18603
18604   x_expand = y_expand = FALSE;
18605
18606   /* note that we don't recurse into children if we're already set to expand;
18607    * this avoids traversing the whole actor tree, even if it may lead to some
18608    * child left with the needs_compute_expand flag set.
18609    */
18610   clutter_actor_iter_init (&iter, self);
18611   while (clutter_actor_iter_next (&iter, &child))
18612     {
18613       x_expand = x_expand ||
18614         clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_HORIZONTAL);
18615
18616       y_expand = y_expand ||
18617         clutter_actor_needs_expand (child, CLUTTER_ORIENTATION_VERTICAL);
18618     }
18619
18620   *x_expand_p = x_expand;
18621   *y_expand_p = y_expand;
18622 }
18623
18624 static void
18625 clutter_actor_compute_expand (ClutterActor *self)
18626 {
18627   if (self->priv->needs_compute_expand)
18628     {
18629       const ClutterLayoutInfo *info;
18630       gboolean x_expand, y_expand;
18631
18632       info = _clutter_actor_get_layout_info_or_defaults (self);
18633
18634       if (self->priv->x_expand_set)
18635         x_expand = info->x_expand;
18636       else
18637         x_expand = FALSE;
18638
18639       if (self->priv->y_expand_set)
18640         y_expand = info->y_expand;
18641       else
18642         y_expand = FALSE;
18643
18644       /* we don't need to recurse down to the children if the
18645        * actor has been forcibly set to expand
18646        */
18647       if (!(self->priv->x_expand_set && self->priv->y_expand_set))
18648         {
18649           if (self->priv->n_children != 0)
18650             {
18651               gboolean *x_expand_p, *y_expand_p;
18652               gboolean ignored = FALSE;
18653
18654               x_expand_p = self->priv->x_expand_set ? &ignored : &x_expand;
18655               y_expand_p = self->priv->y_expand_set ? &ignored : &y_expand;
18656
18657               clutter_actor_compute_expand_recursive (self,
18658                                                       x_expand_p,
18659                                                       y_expand_p);
18660             }
18661         }
18662
18663       self->priv->needs_compute_expand = FALSE;
18664       self->priv->needs_x_expand = (x_expand != FALSE);
18665       self->priv->needs_y_expand = (y_expand != FALSE);
18666     }
18667 }
18668
18669 /**
18670  * clutter_actor_needs_expand:
18671  * @self: a #ClutterActor
18672  * @orientation: the direction of expansion
18673  *
18674  * Checks whether an actor, or any of its children, is set to expand
18675  * horizontally or vertically.
18676  *
18677  * This function should only be called by layout managers that can
18678  * assign extra space to their children.
18679  *
18680  * If you want to know whether the actor was explicitly set to expand,
18681  * use clutter_actor_get_x_expand() or clutter_actor_get_y_expand().
18682  *
18683  * Return value: %TRUE if the actor should expand
18684  *
18685  * Since: 1.12
18686  */
18687 gboolean
18688 clutter_actor_needs_expand (ClutterActor       *self,
18689                             ClutterOrientation  orientation)
18690 {
18691   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
18692
18693   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
18694     return FALSE;
18695
18696   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
18697     return FALSE;
18698
18699   clutter_actor_compute_expand (self);
18700
18701   switch (orientation)
18702     {
18703     case CLUTTER_ORIENTATION_HORIZONTAL:
18704       return self->priv->needs_x_expand;
18705
18706     case CLUTTER_ORIENTATION_VERTICAL:
18707       return self->priv->needs_y_expand;
18708     }
18709
18710   return FALSE;
18711 }