actor: Make add_transition() work regardless of easing state
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010, 2011, 2012 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: The basic element of the scene graph 
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-painting">
119  *   <title>Painting an actor</title>
120  *   <para>There are three ways to paint an actor:</para>
121  *   <itemizedlist>
122  *     <listitem><para>set a delegate #ClutterContent as the value for the
123  *     #ClutterActor:content property of the actor;</para></listitem>
124  *     <listitem><para>subclass #ClutterActor and override the
125  *     #ClutterActorClass.paint_node() virtual function;</para></listitem>
126  *     <listitem><para>subclass #ClutterActor and override the
127  *     #ClutterActorClass.paint() virtual function.</para></listitem>
128  *   </itemizedlist>
129  *   <formalpara>
130  *     <title>Setting the Content property</title>
131  *     <para>A #ClutterContent is a delegate object that takes over the
132  *     painting operation of one, or more actors. The #ClutterContent
133  *     painting will be performed on top of the #ClutterActor:background-color
134  *     of the actor, and before calling the #ClutterActorClass.paint_node()
135  *     virtual function.</para>
136  *     <informalexample><programlisting>
137  * ClutterActor *actor = clutter_actor_new ();
138  *
139  * /&ast; set the bounding box &ast;/
140  * clutter_actor_set_position (actor, 50, 50);
141  * clutter_actor_set_size (actor, 100, 100);
142  *
143  * /&ast; set the content; the image_content variable is set elsewhere &ast;/
144  * clutter_actor_set_content (actor, image_content);
145  *     </programlisting></informalexample>
146  *   </formalpara>
147  *   <formalpara>
148  *     <title>Overriding the paint_node virtual function</title>
149  *     <para>The #ClutterActorClass.paint_node() virtual function is invoked
150  *     whenever an actor needs to be painted. The implementation of the
151  *     virtual function must only paint the contents of the actor itself,
152  *     and not the contents of its children, if the actor has any.</para>
153  *     <para>The #ClutterPaintNode passed to the virtual function is the
154  *     local root of the render tree; any node added to it will be
155  *     rendered at the correct position, as defined by the actor's
156  *     #ClutterActor:allocation.</para>
157  *     <informalexample><programlisting>
158  * static void
159  * my_actor_paint_node (ClutterActor     *actor,
160  *                      ClutterPaintNode *root)
161  * {
162  *   ClutterPaintNode *node;
163  *   ClutterActorBox box;
164  *
165  *   /&ast; where the content of the actor should be painted &ast;/
166  *   clutter_actor_get_allocation_box (actor, &box);
167  *
168  *   /&ast; the cogl_texture variable is set elsewhere &ast;/
169  *   node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170  *                                    CLUTTER_SCALING_FILTER_TRILINEAR,
171  *                                    CLUTTER_SCALING_FILTER_LINEAR);
172  *
173  *   /&ast; paint the content of the node using the allocation &ast;/
174  *   clutter_paint_node_add_rectangle (node, &box);
175  *
176  *   /&ast; add the node, and transfer ownership &ast;/
177  *   clutter_paint_node_add_child (root, node);
178  *   clutter_paint_node_unref (node);
179  * }
180  *     </programlisting></informalexample>
181  *   </formalpara>
182  *   <formalpara>
183  *     <title>Overriding the paint virtual function</title>
184  *     <para>The #ClutterActorClass.paint() virtual function is invoked
185  *     when the #ClutterActor::paint signal is emitted, and after the other
186  *     signal handlers have been invoked. Overriding the paint virtual
187  *     function gives total control to the paint sequence of the actor
188  *     itself, including the children of the actor, if any.</para>
189  *     <warning><para>It is strongly discouraged to override the
190  *     #ClutterActorClass.paint() virtual function, as well as connecting
191  *     to the #ClutterActor::paint signal. These hooks into the paint
192  *     sequence are considered legacy, and will be removed when the Clutter
193  *     API changes.</para></warning>
194  *   </formalpara>
195  * </refsect2>
196  *
197  * <refsect2 id="ClutterActor-events">
198  *   <title>Handling events on an actor</title>
199  *   <para>A #ClutterActor can receive and handle input device events, for
200  *   instance pointer events and key events, as long as its
201  *   #ClutterActor:reactive property is set to %TRUE.</para>
202  *   <para>Once an actor has been determined to be the source of an event,
203  *   Clutter will traverse the scene graph from the top-level actor towards the
204  *   event source, emitting the #ClutterActor::captured-event signal on each
205  *   ancestor until it reaches the source; this phase is also called
206  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
207  *   stopped, the graph is walked backwards, from the source actor to the
208  *   top-level, and the #ClutterActor::event signal, along with other event
209  *   signals if needed, is emitted; this phase is also called <emphasis>the
210  *   bubble phase</emphasis>. At any point of the signal emission, signal
211  *   handlers can stop the propagation through the scene graph by returning
212  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
214  * </refsect2>
215  *
216  * <refsect2 id="ClutterActor-animation">
217  *   <title>Animation</title>
218  *   <para>Animation is a core concept of modern user interfaces; Clutter
219  *   provides a complete and powerful animation framework that automatically
220  *   tweens the actor's state without requiring direct, frame by frame
221  *   manipulation from your application code.</para>
222  *   <formalpara>
223  *     <title>Implicit animations</title>
224  *     <para>The implicit animation model of Clutter assumes that all the
225  *     changes in an actor state should be gradual and asynchronous; Clutter
226  *     will automatically transition an actor's property change between the
227  *     current state and the desired one without manual intervention.</para>
228  *     <para>By default, in the 1.0 API series, the transition happens with
229  *     a duration of zero milliseconds, and the implicit animation is an
230  *     opt in feature to retain backwards compatibility. In order to enable
231  *     implicit animations, it is necessary to change the easing state of
232  *     an actor by using clutter_actor_save_easing_state():</para>
233  *     <informalexample><programlisting>
234  * /&ast; assume that the actor is currently positioned at (100, 100) &ast;/
235  * clutter_actor_save_easing_state (actor);
236  * clutter_actor_set_position (actor, 500, 500);
237  * clutter_actor_restore_easing_state (actor);
238  *     </programlisting></informalexample>
239  *     <para>The example above will trigger an implicit animation of the
240  *     actor between its current position to a new position.</para>
241  *     <para>It is possible to animate multiple properties of an actor
242  *     at the same time, and you can animate multiple actors at the same
243  *     time as well, for instance:</para>
244  *     <informalexample><programlisting>
245  * /&ast; animate the actor's opacity and depth &ast;/
246  * clutter_actor_save_easing_state (actor);
247  * clutter_actor_set_opacity (actor, 0);
248  * clutter_actor_set_depth (actor, -100);
249  * clutter_actor_restore_easing_state (actor);
250  *
251  * /&ast; animate another actor's opacity &ast;/
252  * clutter_actor_save_easing_state (another_actor);
253  * clutter_actor_set_opacity (another_actor, 255);
254  * clutter_actor_set_depth (another_actor, 100);
255  * clutter_actor_restore_easing_state (another_actor);
256  *     </programlisting></informalexample>
257  *     <para>Implicit animations use a default duration of 250 milliseconds,
258  *     and a default easing mode of %CLUTTER_EASE_OUT_CUBIC, unless you call
259  *     clutter_actor_set_easing_mode() and clutter_actor_set_easing_duration()
260  *     after changing the easing state of the actor.</para>
261  *     <para>It is important to note that if you modify the state on an
262  *     animatable property while a transition is in flight, the transition's
263  *     final value will be updated, as well as its duration and progress
264  *     mode by using the current easing state; for instance, in the following
265  *     example:</para>
266  *     <informalexample><programlisting>
267  * clutter_actor_save_easing_state (actor);
268  * clutter_actor_set_x (actor, 200);
269  * clutter_actor_restore_easing_state (actor);
270  *
271  * clutter_actor_save_easing_state (actor);
272  * clutter_actor_set_x (actor, 100);
273  * clutter_actor_restore_easing_state (actor);
274  *     </programlisting></informalexample>
275  *     <para>the first call to clutter_actor_set_x() will begin a transition
276  *     of the #ClutterActor:x property to the value of 200; the second call
277  *     to clutter_actor_set_x() will change the transition's final value to
278  *     100.</para>
279  *     <para>It is possible to retrieve the #ClutterTransition used by the
280  *     animatable properties by using clutter_actor_get_transition() and using
281  *     the property name as the transition name.</para>
282  *   </formalpara>
283  *   <formalpara>
284  *     <title>Explicit animations</title>
285  *     <para>The explicit animation model supported by Clutter requires that
286  *     you create a #ClutterTransition object, and set the initial and
287  *     final values. The transition will not start unless you add it to the
288  *     #ClutterActor.</para>
289  *     <informalexample><programlisting>
290  * ClutterTransition *transition;
291  *
292  * transition = clutter_property_transition_new ("opacity");
293  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000);
294  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
295  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
296  * clutter_transition_set_from (transition, G_TYPE_UINT, 255);
297  * clutter_transition_set_to (transition, G_TYPE_UINT, 0);
298  *
299  * clutter_actor_add_transition (actor, "animate-opacity", transition);
300  *     </programlisting></informalexample>
301  *     <para>The example above will animate the #ClutterActor:opacity property
302  *     of an actor between fully opaque and fully transparent, and back, over
303  *     a span of 3 seconds. The animation does not begin until it is added to
304  *     the actor.</para>
305  *     <para>The explicit animation API should also be used when using custom
306  *     animatable properties for #ClutterAction, #ClutterConstraint, and
307  *     #ClutterEffect instances associated to an actor; see the section on
308  *     <ulink linkend="ClutterActor-custom-animatable-properties">custom
309  *     animatable properties below</ulink> for an example.</para>
310  *     <para>Finally, explicit animations are useful for creating animations
311  *     that run continuously, for instance:</para>
312  *     <informalexample><programlisting>
313  * /&ast; this animation will pulse the actor's opacity continuously &ast;/
314  * ClutterTransition *transition;
315  * ClutterInterval *interval;
316  *
317  * transition = clutter_property_transition_new ("opacity");
318  *
319  * /&ast; we want to animate the opacity between 0 and 255 &ast;/
320  * clutter_transition_set_from (transition, G_TYPE_UINT, 0);
321  * clutter_transition_set_to (transition, G_TYPE_UINT, 255);
322  *
323  * /&ast; over a one second duration, running an infinite amount of times &ast;/
324  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
325  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
326  *
327  * /&ast; we want to fade in and out, so we need to auto-reverse the transition &ast;/
328  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
329  *
330  * /&ast; and we want to use an easing function that eases both in and out &ast;/
331  * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
332  *                                     CLUTTER_EASE_IN_OUT_CUBIC);
333  *
334  * /&ast; add the transition to the desired actor; this will
335  *  &ast; start the animation.
336  *  &ast;/
337  * clutter_actor_add_transition (actor, "opacityAnimation", transition);
338  *     </programlisting></informalexample>
339  *   </formalpara>
340  * </refsect2>
341  *
342  * <refsect2 id="ClutterActor-subclassing">
343  *   <title>Implementing an actor</title>
344  *   <para>Careful consideration should be given when deciding to implement
345  *   a #ClutterActor sub-class. It is generally recommended to implement a
346  *   sub-class of #ClutterActor only for actors that should be used as leaf
347  *   nodes of a scene graph.</para>
348  *   <para>If your actor should be painted in a custom way, you should
349  *   override the #ClutterActor::paint signal class handler. You can either
350  *   opt to chain up to the parent class implementation or decide to fully
351  *   override the default paint implementation; Clutter will set up the
352  *   transformations and clip regions prior to emitting the #ClutterActor::paint
353  *   signal.</para>
354  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
355  *   #ClutterActorClass.get_preferred_height() virtual functions it is
356  *   possible to change or provide the preferred size of an actor; similarly,
357  *   by overriding the #ClutterActorClass.allocate() virtual function it is
358  *   possible to control the layout of the children of an actor. Make sure to
359  *   always chain up to the parent implementation of the
360  *   #ClutterActorClass.allocate() virtual function.</para>
361  *   <para>In general, it is strongly encouraged to use delegation and
362  *   composition instead of direct subclassing.</para>
363  * </refsect2>
364  *
365  * <refsect2 id="ClutterActor-script">
366  *   <title>ClutterActor custom properties for #ClutterScript</title>
367  *   <para>#ClutterActor defines a custom "rotation" property which
368  *   allows a short-hand description of the rotations to be applied
369  *   to an actor.</para>
370  *   <para>The syntax of the "rotation" property is the following:</para>
371  *   <informalexample>
372  *     <programlisting>
373  * "rotation" : [
374  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
375  * ]
376  *     </programlisting>
377  *   </informalexample>
378  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
379  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
380  *   floating point value representing the rotation angle on the given axis,
381  *   in degrees.</para>
382  *   <para>The <emphasis>center</emphasis> array is optional, and if present
383  *   it must contain the center of rotation as described by two coordinates:
384  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
385  *   "z-axis".</para>
386  *   <para>#ClutterActor will also parse every positional and dimensional
387  *   property defined as a string through clutter_units_from_string(); you
388  *   should read the documentation for the #ClutterUnits parser format for
389  *   the valid units and syntax.</para>
390  * </refsect2>
391  *
392  * <refsect2 id="ClutterActor-custom-animatable-properties">
393  *   <title>Custom animatable properties</title>
394  *   <para>#ClutterActor allows accessing properties of #ClutterAction,
395  *   #ClutterEffect, and #ClutterConstraint instances associated to an actor
396  *   instance for animation purposes.</para>
397  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
398  *   property it is necessary to set the #ClutterActorMeta:name property on the
399  *   given action or constraint.</para>
400  *   <para>The property can be accessed using the following syntax:</para>
401  *   <informalexample>
402  *     <programlisting>
403  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
404  *     </programlisting>
405  *   </informalexample>
406  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
407  *   <para>The <emphasis>section</emphasis> fragment can be one between
408  *   "actions", "constraints" and "effects".</para>
409  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
410  *   action or constraint, as specified by the #ClutterActorMeta:name
411  *   property.</para>
412  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
413  *   action or constraint property to be animated.</para>
414  *   <para>The example below animates a #ClutterBindConstraint applied to an
415  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
416  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
417  *   its initial state is overlapping the actor to which is bound to.</para>
418  *   <informalexample><programlisting>
419  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
420  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
421  * clutter_actor_add_constraint (rect, constraint);
422  *
423  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
424  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
425  * clutter_actor_add_constraint (rect, constraint);
426  *
427  * clutter_actor_set_reactive (origin, TRUE);
428  *
429  * g_signal_connect (origin, "button-press-event",
430  *                   G_CALLBACK (on_button_press),
431  *                   rect);
432  *   </programlisting></informalexample>
433  *   <para>On button press, the rectangle "slides" from behind the actor to
434  *   which is bound to, using the #ClutterBindConstraint:offset property to
435  *   achieve the effect:</para>
436  *   <informalexample><programlisting>
437  * gboolean
438  * on_button_press (ClutterActor *origin,
439  *                  ClutterEvent *event,
440  *                  ClutterActor *rect)
441  * {
442  *   ClutterTransition *transition;
443  *   ClutterInterval *interval;
444  *
445  *   /&ast; the offset that we want to apply; this will make the actor
446  *    &ast; slide in from behind the origin and rest at the right of
447  *    &ast; the origin, plus a padding value.
448  *    &ast;/
449  *   float new_offset = clutter_actor_get_width (origin) + h_padding;
450  *
451  *   /&ast; the property we wish to animate; the "@constraints" section
452  *    &ast; tells Clutter to check inside the constraints associated
453  *    &ast; with the actor; the "bind-x" section is the name of the
454  *    &ast; constraint; and the "offset" is the name of the property
455  *    &ast; on the constraint.
456  *    &ast;/
457  *   const char *prop = "@constraints.bind-x.offset";
458  *
459  *   /&ast; create a new transition for the given property &ast;/
460  *   transition = clutter_property_transition_new (prop);
461  *
462  *   /&ast; set the easing mode and duration &ast;/
463  *   clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
464  *                                       CLUTTER_EASE_OUT_CUBIC);
465  *   clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
466  *
467  *   /&ast; create the interval with the initial and final values &ast;/
468  *   interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
469  *   clutter_transition_set_interval (transition, interval);
470  *
471  *   /&ast; add the transition to the actor; this causes the animation
472  *    &ast; to start. the name "offsetAnimation" can be used to retrieve
473  *    &ast; the transition later.
474  *    &ast;/
475  *   clutter_actor_add_transition (rect, "offsetAnimation", transition);
476  *
477  *   /&ast; we handled the event &ast;/
478  *   return CLUTTER_EVENT_STOP;
479  * }
480  *   </programlisting></informalexample>
481  * </refsect2>
482  */
483
484 /**
485  * CLUTTER_ACTOR_IS_MAPPED:
486  * @a: a #ClutterActor
487  *
488  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
489  *
490  * The mapped state is set when the actor is visible and all its parents up
491  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
492  *
493  * This check can be used to see if an actor is going to be painted, as only
494  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
495  *
496  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
497  * not be checked directly; instead, the recommended usage is to connect a
498  * handler on the #GObject::notify signal for the #ClutterActor:mapped
499  * property of #ClutterActor, and check the presence of
500  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
501  *
502  * It is also important to note that Clutter may delay the changes of
503  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
504  * limitations, or during the reparenting of an actor, to optimize
505  * unnecessary (and potentially expensive) state changes.
506  *
507  * Since: 0.2
508  */
509
510 /**
511  * CLUTTER_ACTOR_IS_REALIZED:
512  * @a: a #ClutterActor
513  *
514  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
515  *
516  * The realized state has an actor-dependant interpretation. If an
517  * actor wants to delay allocating resources until it is attached to a
518  * stage, it may use the realize state to do so. However it is
519  * perfectly acceptable for an actor to allocate Cogl resources before
520  * being realized because there is only one drawing context used by Clutter
521  * so any resources will work on any stage.  If an actor is mapped it
522  * must also be realized, but an actor can be realized and unmapped
523  * (this is so hiding an actor temporarily doesn't do an expensive
524  * unrealize/realize).
525  *
526  * To be realized an actor must be inside a stage, and all its parents
527  * must be realized.
528  *
529  * Since: 0.2
530  */
531
532 /**
533  * CLUTTER_ACTOR_IS_VISIBLE:
534  * @a: a #ClutterActor
535  *
536  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
537  * Equivalent to the ClutterActor::visible object property.
538  *
539  * Note that an actor is only painted onscreen if it's mapped, which
540  * means it's visible, and all its parents are visible, and one of the
541  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
542  *
543  * Since: 0.2
544  */
545
546 /**
547  * CLUTTER_ACTOR_IS_REACTIVE:
548  * @a: a #ClutterActor
549  *
550  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
551  *
552  * Only reactive actors will receive event-related signals.
553  *
554  * Since: 0.6
555  */
556
557 #ifdef HAVE_CONFIG_H
558 #include "config.h"
559 #endif
560
561 #include <math.h>
562
563 #include <gobject/gvaluecollector.h>
564
565 #include <cogl/cogl.h>
566
567 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
568 #define CLUTTER_ENABLE_EXPERIMENTAL_API
569
570 #include "clutter-actor-private.h"
571
572 #include "clutter-action.h"
573 #include "clutter-actor-meta-private.h"
574 #include "clutter-animatable.h"
575 #include "clutter-color-static.h"
576 #include "clutter-color.h"
577 #include "clutter-constraint.h"
578 #include "clutter-container.h"
579 #include "clutter-content-private.h"
580 #include "clutter-debug.h"
581 #include "clutter-effect-private.h"
582 #include "clutter-enum-types.h"
583 #include "clutter-fixed-layout.h"
584 #include "clutter-flatten-effect.h"
585 #include "clutter-interval.h"
586 #include "clutter-main.h"
587 #include "clutter-marshal.h"
588 #include "clutter-paint-nodes.h"
589 #include "clutter-paint-node-private.h"
590 #include "clutter-paint-volume-private.h"
591 #include "clutter-private.h"
592 #include "clutter-profile.h"
593 #include "clutter-property-transition.h"
594 #include "clutter-scriptable.h"
595 #include "clutter-script-private.h"
596 #include "clutter-stage-private.h"
597 #include "clutter-timeline.h"
598 #include "clutter-transition.h"
599 #include "clutter-units.h"
600
601 #include "deprecated/clutter-actor.h"
602 #include "deprecated/clutter-behaviour.h"
603 #include "deprecated/clutter-container.h"
604
605 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
606 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
607
608 /* Internal enum used to control mapped state update.  This is a hint
609  * which indicates when to do something other than just enforce
610  * invariants.
611  */
612 typedef enum {
613   MAP_STATE_CHECK,           /* just enforce invariants. */
614   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
615                               * used when about to unparent.
616                               */
617   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
618                               * used to set mapped on toplevels.
619                               */
620   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
621                               * used just before unmapping parent.
622                               */
623 } MapStateChange;
624
625 /* 3 entries should be a good compromise, few layout managers
626  * will ask for 3 different preferred size in each allocation cycle */
627 #define N_CACHED_SIZE_REQUESTS 3
628
629 struct _ClutterActorPrivate
630 {
631   /* request mode */
632   ClutterRequestMode request_mode;
633
634   /* our cached size requests for different width / height */
635   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
636   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
637
638   /* An age of 0 means the entry is not set */
639   guint cached_height_age;
640   guint cached_width_age;
641
642   /* the bounding box of the actor, relative to the parent's
643    * allocation
644    */
645   ClutterActorBox allocation;
646   ClutterAllocationFlags allocation_flags;
647
648   /* clip, in actor coordinates */
649   cairo_rectangle_t clip;
650
651   /* the cached transformation matrix; see apply_transform() */
652   CoglMatrix transform;
653
654   guint8 opacity;
655   gint opacity_override;
656
657   ClutterOffscreenRedirect offscreen_redirect;
658
659   /* This is an internal effect used to implement the
660      offscreen-redirect property */
661   ClutterEffect *flatten_effect;
662
663   /* scene graph */
664   ClutterActor *parent;
665   ClutterActor *prev_sibling;
666   ClutterActor *next_sibling;
667   ClutterActor *first_child;
668   ClutterActor *last_child;
669
670   gint n_children;
671
672   /* tracks whenever the children of an actor are changed; the
673    * age is incremented by 1 whenever an actor is added or
674    * removed. the age is not incremented when the first or the
675    * last child pointers are changed, or when grandchildren of
676    * an actor are changed.
677    */
678   gint age;
679
680   gchar *name; /* a non-unique name, used for debugging */
681   guint32 id; /* unique id, used for backward compatibility */
682
683   gint32 pick_id; /* per-stage unique id, used for picking */
684
685   /* a back-pointer to the Pango context that we can use
686    * to create pre-configured PangoLayout
687    */
688   PangoContext *pango_context;
689
690   /* the text direction configured for this child - either by
691    * application code, or by the actor's parent
692    */
693   ClutterTextDirection text_direction;
694
695   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
696   gint internal_child;
697
698   /* meta classes */
699   ClutterMetaGroup *actions;
700   ClutterMetaGroup *constraints;
701   ClutterMetaGroup *effects;
702
703   /* delegate object used to allocate the children of this actor */
704   ClutterLayoutManager *layout_manager;
705
706   /* delegate object used to paint the contents of this actor */
707   ClutterContent *content;
708
709   ClutterActorBox content_box;
710   ClutterContentGravity content_gravity;
711   ClutterScalingFilter min_filter;
712   ClutterScalingFilter mag_filter;
713
714   /* used when painting, to update the paint volume */
715   ClutterEffect *current_effect;
716
717   /* This is used to store an effect which needs to be redrawn. A
718      redraw can be queued to start from a particular effect. This is
719      used by parametrised effects that can cache an image of the
720      actor. If a parameter of the effect changes then it only needs to
721      redraw the cached image, not the actual actor. The pointer is
722      only valid if is_dirty == TRUE. If the pointer is NULL then the
723      whole actor is dirty. */
724   ClutterEffect *effect_to_redraw;
725
726   /* This is used when painting effects to implement the
727      clutter_actor_continue_paint() function. It points to the node in
728      the list of effects that is next in the chain */
729   const GList *next_effect_to_paint;
730
731   ClutterPaintVolume paint_volume;
732
733   /* NB: This volume isn't relative to this actor, it is in eye
734    * coordinates so that it can remain valid after the actor changes.
735    */
736   ClutterPaintVolume last_paint_volume;
737
738   ClutterStageQueueRedrawEntry *queue_redraw_entry;
739
740   ClutterColor bg_color;
741
742   /* bitfields */
743
744   /* fixed position and sizes */
745   guint position_set                : 1;
746   guint min_width_set               : 1;
747   guint min_height_set              : 1;
748   guint natural_width_set           : 1;
749   guint natural_height_set          : 1;
750   /* cached request is invalid (implies allocation is too) */
751   guint needs_width_request         : 1;
752   /* cached request is invalid (implies allocation is too) */
753   guint needs_height_request        : 1;
754   /* cached allocation is invalid (request has changed, probably) */
755   guint needs_allocation            : 1;
756   guint show_on_set_parent          : 1;
757   guint has_clip                    : 1;
758   guint clip_to_allocation          : 1;
759   guint enable_model_view_transform : 1;
760   guint enable_paint_unmapped       : 1;
761   guint has_pointer                 : 1;
762   guint propagated_one_redraw       : 1;
763   guint paint_volume_valid          : 1;
764   guint last_paint_volume_valid     : 1;
765   guint in_clone_paint              : 1;
766   guint transform_valid             : 1;
767   /* This is TRUE if anything has queued a redraw since we were last
768      painted. In this case effect_to_redraw will point to an effect
769      the redraw was queued from or it will be NULL if the redraw was
770      queued without an effect. */
771   guint is_dirty                    : 1;
772   guint bg_color_set                : 1;
773   guint content_box_valid           : 1;
774 };
775
776 enum
777 {
778   PROP_0,
779
780   PROP_NAME,
781
782   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
783    * when set they force a size request, when gotten they
784    * get the allocation if the allocation is valid, and the
785    * request otherwise
786    */
787   PROP_X,
788   PROP_Y,
789   PROP_WIDTH,
790   PROP_HEIGHT,
791
792   PROP_POSITION,
793   PROP_SIZE,
794
795   /* Then the rest of these size-related properties are the "actual"
796    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
797    */
798   PROP_FIXED_X,
799   PROP_FIXED_Y,
800
801   PROP_FIXED_POSITION_SET,
802
803   PROP_MIN_WIDTH,
804   PROP_MIN_WIDTH_SET,
805
806   PROP_MIN_HEIGHT,
807   PROP_MIN_HEIGHT_SET,
808
809   PROP_NATURAL_WIDTH,
810   PROP_NATURAL_WIDTH_SET,
811
812   PROP_NATURAL_HEIGHT,
813   PROP_NATURAL_HEIGHT_SET,
814
815   PROP_REQUEST_MODE,
816
817   /* Allocation properties are read-only */
818   PROP_ALLOCATION,
819
820   PROP_DEPTH,
821
822   PROP_CLIP,
823   PROP_HAS_CLIP,
824   PROP_CLIP_TO_ALLOCATION,
825
826   PROP_OPACITY,
827
828   PROP_OFFSCREEN_REDIRECT,
829
830   PROP_VISIBLE,
831   PROP_MAPPED,
832   PROP_REALIZED,
833   PROP_REACTIVE,
834
835   PROP_SCALE_X,
836   PROP_SCALE_Y,
837   PROP_SCALE_CENTER_X,
838   PROP_SCALE_CENTER_Y,
839   PROP_SCALE_GRAVITY,
840
841   PROP_ROTATION_ANGLE_X,
842   PROP_ROTATION_ANGLE_Y,
843   PROP_ROTATION_ANGLE_Z,
844   PROP_ROTATION_CENTER_X,
845   PROP_ROTATION_CENTER_Y,
846   PROP_ROTATION_CENTER_Z,
847   /* This property only makes sense for the z rotation because the
848      others would depend on the actor having a size along the
849      z-axis */
850   PROP_ROTATION_CENTER_Z_GRAVITY,
851
852   PROP_ANCHOR_X,
853   PROP_ANCHOR_Y,
854   PROP_ANCHOR_GRAVITY,
855
856   PROP_SHOW_ON_SET_PARENT,
857
858   PROP_TEXT_DIRECTION,
859   PROP_HAS_POINTER,
860
861   PROP_ACTIONS,
862   PROP_CONSTRAINTS,
863   PROP_EFFECT,
864
865   PROP_LAYOUT_MANAGER,
866
867   PROP_X_ALIGN,
868   PROP_Y_ALIGN,
869   PROP_MARGIN_TOP,
870   PROP_MARGIN_BOTTOM,
871   PROP_MARGIN_LEFT,
872   PROP_MARGIN_RIGHT,
873
874   PROP_BACKGROUND_COLOR,
875   PROP_BACKGROUND_COLOR_SET,
876
877   PROP_FIRST_CHILD,
878   PROP_LAST_CHILD,
879
880   PROP_CONTENT,
881   PROP_CONTENT_GRAVITY,
882   PROP_CONTENT_BOX,
883   PROP_MINIFICATION_FILTER,
884   PROP_MAGNIFICATION_FILTER,
885
886   PROP_LAST
887 };
888
889 static GParamSpec *obj_props[PROP_LAST];
890
891 enum
892 {
893   SHOW,
894   HIDE,
895   DESTROY,
896   PARENT_SET,
897   KEY_FOCUS_IN,
898   KEY_FOCUS_OUT,
899   PAINT,
900   PICK,
901   REALIZE,
902   UNREALIZE,
903   QUEUE_REDRAW,
904   QUEUE_RELAYOUT,
905   EVENT,
906   CAPTURED_EVENT,
907   BUTTON_PRESS_EVENT,
908   BUTTON_RELEASE_EVENT,
909   SCROLL_EVENT,
910   KEY_PRESS_EVENT,
911   KEY_RELEASE_EVENT,
912   MOTION_EVENT,
913   ENTER_EVENT,
914   LEAVE_EVENT,
915   ALLOCATION_CHANGED,
916   TRANSITIONS_COMPLETED,
917
918   LAST_SIGNAL
919 };
920
921 static guint actor_signals[LAST_SIGNAL] = { 0, };
922
923 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
924 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
925 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
926 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
927
928 /* These setters are all static for now, maybe they should be in the
929  * public API, but they are perhaps obscure enough to leave only as
930  * properties
931  */
932 static void clutter_actor_set_min_width          (ClutterActor *self,
933                                                   gfloat        min_width);
934 static void clutter_actor_set_min_height         (ClutterActor *self,
935                                                   gfloat        min_height);
936 static void clutter_actor_set_natural_width      (ClutterActor *self,
937                                                   gfloat        natural_width);
938 static void clutter_actor_set_natural_height     (ClutterActor *self,
939                                                   gfloat        natural_height);
940 static void clutter_actor_set_min_width_set      (ClutterActor *self,
941                                                   gboolean      use_min_width);
942 static void clutter_actor_set_min_height_set     (ClutterActor *self,
943                                                   gboolean      use_min_height);
944 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
945                                                   gboolean  use_natural_width);
946 static void clutter_actor_set_natural_height_set (ClutterActor *self,
947                                                   gboolean  use_natural_height);
948 static void clutter_actor_update_map_state       (ClutterActor  *self,
949                                                   MapStateChange change);
950 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
951
952 /* Helper routines for managing anchor coords */
953 static void clutter_anchor_coord_get_units (ClutterActor      *self,
954                                             const AnchorCoord *coord,
955                                             gfloat            *x,
956                                             gfloat            *y,
957                                             gfloat            *z);
958 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
959                                             gfloat             x,
960                                             gfloat             y,
961                                             gfloat             z);
962
963 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
964 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
965                                                         ClutterGravity     gravity);
966
967 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
968
969 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
970
971 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
972                                                                ClutterActor *ancestor,
973                                                                CoglMatrix *matrix);
974
975 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
976
977 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
978
979 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
980                                                                 const ClutterColor *color);
981
982 static void on_layout_manager_changed (ClutterLayoutManager *manager,
983                                        ClutterActor         *self);
984
985 /* Helper macro which translates by the anchor coord, applies the
986    given transformation and then translates back */
987 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
988   gfloat _tx, _ty, _tz;                                                \
989   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
990   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
991   { _transform; }                                                      \
992   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
993
994 static GQuark quark_shader_data = 0;
995 static GQuark quark_actor_layout_info = 0;
996 static GQuark quark_actor_transform_info = 0;
997 static GQuark quark_actor_animation_info = 0;
998
999 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
1000                          clutter_actor,
1001                          G_TYPE_INITIALLY_UNOWNED,
1002                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1003                                                 clutter_container_iface_init)
1004                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1005                                                 clutter_scriptable_iface_init)
1006                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1007                                                 clutter_animatable_iface_init)
1008                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1009                                                 atk_implementor_iface_init));
1010
1011 /*< private >
1012  * clutter_actor_get_debug_name:
1013  * @actor: a #ClutterActor
1014  *
1015  * Retrieves a printable name of @actor for debugging messages
1016  *
1017  * Return value: a string with a printable name
1018  */
1019 const gchar *
1020 _clutter_actor_get_debug_name (ClutterActor *actor)
1021 {
1022   return actor->priv->name != NULL ? actor->priv->name
1023                                    : G_OBJECT_TYPE_NAME (actor);
1024 }
1025
1026 #ifdef CLUTTER_ENABLE_DEBUG
1027 /* XXX - this is for debugging only, remove once working (or leave
1028  * in only in some debug mode). Should leave it for a little while
1029  * until we're confident in the new map/realize/visible handling.
1030  */
1031 static inline void
1032 clutter_actor_verify_map_state (ClutterActor *self)
1033 {
1034   ClutterActorPrivate *priv = self->priv;
1035
1036   if (CLUTTER_ACTOR_IS_REALIZED (self))
1037     {
1038       /* all bets are off during reparent when we're potentially realized,
1039        * but should not be according to invariants
1040        */
1041       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1042         {
1043           if (priv->parent == NULL)
1044             {
1045               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1046                 {
1047                 }
1048               else
1049                 g_warning ("Realized non-toplevel actor '%s' should "
1050                            "have a parent",
1051                            _clutter_actor_get_debug_name (self));
1052             }
1053           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1054             {
1055               g_warning ("Realized actor %s has an unrealized parent %s",
1056                          _clutter_actor_get_debug_name (self),
1057                          _clutter_actor_get_debug_name (priv->parent));
1058             }
1059         }
1060     }
1061
1062   if (CLUTTER_ACTOR_IS_MAPPED (self))
1063     {
1064       if (!CLUTTER_ACTOR_IS_REALIZED (self))
1065         g_warning ("Actor '%s' is mapped but not realized",
1066                    _clutter_actor_get_debug_name (self));
1067
1068       /* remaining bets are off during reparent when we're potentially
1069        * mapped, but should not be according to invariants
1070        */
1071       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1072         {
1073           if (priv->parent == NULL)
1074             {
1075               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1076                 {
1077                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1078                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1079                     {
1080                       g_warning ("Toplevel actor '%s' is mapped "
1081                                  "but not visible",
1082                                  _clutter_actor_get_debug_name (self));
1083                     }
1084                 }
1085               else
1086                 {
1087                   g_warning ("Mapped actor '%s' should have a parent",
1088                              _clutter_actor_get_debug_name (self));
1089                 }
1090             }
1091           else
1092             {
1093               ClutterActor *iter = self;
1094
1095               /* check for the enable_paint_unmapped flag on the actor
1096                * and parents; if the flag is enabled at any point of this
1097                * branch of the scene graph then all the later checks
1098                * become pointless
1099                */
1100               while (iter != NULL)
1101                 {
1102                   if (iter->priv->enable_paint_unmapped)
1103                     return;
1104
1105                   iter = iter->priv->parent;
1106                 }
1107
1108               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1109                 {
1110                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1111                              "is not visible",
1112                              _clutter_actor_get_debug_name (self),
1113                              _clutter_actor_get_debug_name (priv->parent));
1114                 }
1115
1116               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1117                 {
1118                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1119                              "is not realized",
1120                              _clutter_actor_get_debug_name (self),
1121                              _clutter_actor_get_debug_name (priv->parent));
1122                 }
1123
1124               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1125                 {
1126                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1127                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1128                                "parent '%s' is not mapped",
1129                                _clutter_actor_get_debug_name (self),
1130                                _clutter_actor_get_debug_name (priv->parent));
1131                 }
1132             }
1133         }
1134     }
1135 }
1136
1137 #endif /* CLUTTER_ENABLE_DEBUG */
1138
1139 static void
1140 clutter_actor_set_mapped (ClutterActor *self,
1141                           gboolean      mapped)
1142 {
1143   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1144     return;
1145
1146   if (mapped)
1147     {
1148       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1149       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1150     }
1151   else
1152     {
1153       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1154       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1155     }
1156 }
1157
1158 /* this function updates the mapped and realized states according to
1159  * invariants, in the appropriate order.
1160  */
1161 static void
1162 clutter_actor_update_map_state (ClutterActor  *self,
1163                                 MapStateChange change)
1164 {
1165   gboolean was_mapped;
1166
1167   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1168
1169   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1170     {
1171       /* the mapped flag on top-level actors must be set by the
1172        * per-backend implementation because it might be asynchronous.
1173        *
1174        * That is, the MAPPED flag on toplevels currently tracks the X
1175        * server mapped-ness of the window, while the expected behavior
1176        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1177        * This creates some weird complexity by breaking the invariant
1178        * that if we're visible and all ancestors shown then we are
1179        * also mapped - instead, we are mapped if all ancestors
1180        * _possibly excepting_ the stage are mapped. The stage
1181        * will map/unmap for example when it is minimized or
1182        * moved to another workspace.
1183        *
1184        * So, the only invariant on the stage is that if visible it
1185        * should be realized, and that it has to be visible to be
1186        * mapped.
1187        */
1188       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1189         clutter_actor_realize (self);
1190
1191       switch (change)
1192         {
1193         case MAP_STATE_CHECK:
1194           break;
1195
1196         case MAP_STATE_MAKE_MAPPED:
1197           g_assert (!was_mapped);
1198           clutter_actor_set_mapped (self, TRUE);
1199           break;
1200
1201         case MAP_STATE_MAKE_UNMAPPED:
1202           g_assert (was_mapped);
1203           clutter_actor_set_mapped (self, FALSE);
1204           break;
1205
1206         case MAP_STATE_MAKE_UNREALIZED:
1207           /* we only use MAKE_UNREALIZED in unparent,
1208            * and unparenting a stage isn't possible.
1209            * If someone wants to just unrealize a stage
1210            * then clutter_actor_unrealize() doesn't
1211            * go through this codepath.
1212            */
1213           g_warning ("Trying to force unrealize stage is not allowed");
1214           break;
1215         }
1216
1217       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1218           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1219           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1220         {
1221           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1222                      "it is somehow still mapped",
1223                      _clutter_actor_get_debug_name (self));
1224         }
1225     }
1226   else
1227     {
1228       ClutterActorPrivate *priv = self->priv;
1229       ClutterActor *parent = priv->parent;
1230       gboolean should_be_mapped;
1231       gboolean may_be_realized;
1232       gboolean must_be_realized;
1233
1234       should_be_mapped = FALSE;
1235       may_be_realized = TRUE;
1236       must_be_realized = FALSE;
1237
1238       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1239         {
1240           may_be_realized = FALSE;
1241         }
1242       else
1243         {
1244           /* Maintain invariant that if parent is mapped, and we are
1245            * visible, then we are mapped ...  unless parent is a
1246            * stage, in which case we map regardless of parent's map
1247            * state but do require stage to be visible and realized.
1248            *
1249            * If parent is realized, that does not force us to be
1250            * realized; but if parent is unrealized, that does force
1251            * us to be unrealized.
1252            *
1253            * The reason we don't force children to realize with
1254            * parents is _clutter_actor_rerealize(); if we require that
1255            * a realized parent means children are realized, then to
1256            * unrealize an actor we would have to unrealize its
1257            * parents, which would end up meaning unrealizing and
1258            * hiding the entire stage. So we allow unrealizing a
1259            * child (as long as that child is not mapped) while that
1260            * child still has a realized parent.
1261            *
1262            * Also, if we unrealize from leaf nodes to root, and
1263            * realize from root to leaf, the invariants are never
1264            * violated if we allow children to be unrealized
1265            * while parents are realized.
1266            *
1267            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1268            * to force us to unmap, even though parent is still
1269            * mapped. This is because we're unmapping from leaf nodes
1270            * up to root nodes.
1271            */
1272           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1273               change != MAP_STATE_MAKE_UNMAPPED)
1274             {
1275               gboolean parent_is_visible_realized_toplevel;
1276
1277               parent_is_visible_realized_toplevel =
1278                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1279                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1280                  CLUTTER_ACTOR_IS_REALIZED (parent));
1281
1282               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1283                   parent_is_visible_realized_toplevel)
1284                 {
1285                   must_be_realized = TRUE;
1286                   should_be_mapped = TRUE;
1287                 }
1288             }
1289
1290           /* if the actor has been set to be painted even if unmapped
1291            * then we should map it and check for realization as well;
1292            * this is an override for the branch of the scene graph
1293            * which begins with this node
1294            */
1295           if (priv->enable_paint_unmapped)
1296             {
1297               if (priv->parent == NULL)
1298                 g_warning ("Attempting to map an unparented actor '%s'",
1299                            _clutter_actor_get_debug_name (self));
1300
1301               should_be_mapped = TRUE;
1302               must_be_realized = TRUE;
1303             }
1304
1305           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1306             may_be_realized = FALSE;
1307         }
1308
1309       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1310         {
1311           if (parent == NULL)
1312             g_warning ("Attempting to map a child that does not "
1313                        "meet the necessary invariants: the actor '%s' "
1314                        "has no parent",
1315                        _clutter_actor_get_debug_name (self));
1316           else
1317             g_warning ("Attempting to map a child that does not "
1318                        "meet the necessary invariants: the actor '%s' "
1319                        "is parented to an unmapped actor '%s'",
1320                        _clutter_actor_get_debug_name (self),
1321                        _clutter_actor_get_debug_name (priv->parent));
1322         }
1323
1324       /* If in reparent, we temporarily suspend unmap and unrealize.
1325        *
1326        * We want to go in the order "realize, map" and "unmap, unrealize"
1327        */
1328
1329       /* Unmap */
1330       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1331         clutter_actor_set_mapped (self, FALSE);
1332
1333       /* Realize */
1334       if (must_be_realized)
1335         clutter_actor_realize (self);
1336
1337       /* if we must be realized then we may be, presumably */
1338       g_assert (!(must_be_realized && !may_be_realized));
1339
1340       /* Unrealize */
1341       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1342         clutter_actor_unrealize_not_hiding (self);
1343
1344       /* Map */
1345       if (should_be_mapped)
1346         {
1347           if (!must_be_realized)
1348             g_warning ("Somehow we think actor '%s' should be mapped but "
1349                        "not realized, which isn't allowed",
1350                        _clutter_actor_get_debug_name (self));
1351
1352           /* realization is allowed to fail (though I don't know what
1353            * an app is supposed to do about that - shouldn't it just
1354            * be a g_error? anyway, we have to avoid mapping if this
1355            * happens)
1356            */
1357           if (CLUTTER_ACTOR_IS_REALIZED (self))
1358             clutter_actor_set_mapped (self, TRUE);
1359         }
1360     }
1361
1362 #ifdef CLUTTER_ENABLE_DEBUG
1363   /* check all invariants were kept */
1364   clutter_actor_verify_map_state (self);
1365 #endif
1366 }
1367
1368 static void
1369 clutter_actor_real_map (ClutterActor *self)
1370 {
1371   ClutterActorPrivate *priv = self->priv;
1372   ClutterActor *stage, *iter;
1373
1374   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1375
1376   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1377                 _clutter_actor_get_debug_name (self));
1378
1379   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1380
1381   stage = _clutter_actor_get_stage_internal (self);
1382   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1383
1384   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1385                 priv->pick_id,
1386                 _clutter_actor_get_debug_name (self));
1387
1388   /* notify on parent mapped before potentially mapping
1389    * children, so apps see a top-down notification.
1390    */
1391   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1392
1393   for (iter = self->priv->first_child;
1394        iter != NULL;
1395        iter = iter->priv->next_sibling)
1396     {
1397       clutter_actor_map (iter);
1398     }
1399 }
1400
1401 /**
1402  * clutter_actor_map:
1403  * @self: A #ClutterActor
1404  *
1405  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1406  * and realizes its children if they are visible. Does nothing if the
1407  * actor is not visible.
1408  *
1409  * Calling this function is strongly disencouraged: the default
1410  * implementation of #ClutterActorClass.map() will map all the children
1411  * of an actor when mapping its parent.
1412  *
1413  * When overriding map, it is mandatory to chain up to the parent
1414  * implementation.
1415  *
1416  * Since: 1.0
1417  */
1418 void
1419 clutter_actor_map (ClutterActor *self)
1420 {
1421   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1422
1423   if (CLUTTER_ACTOR_IS_MAPPED (self))
1424     return;
1425
1426   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1427     return;
1428
1429   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1430 }
1431
1432 static void
1433 clutter_actor_real_unmap (ClutterActor *self)
1434 {
1435   ClutterActorPrivate *priv = self->priv;
1436   ClutterActor *iter;
1437
1438   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1439
1440   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1441                 _clutter_actor_get_debug_name (self));
1442
1443   for (iter = self->priv->first_child;
1444        iter != NULL;
1445        iter = iter->priv->next_sibling)
1446     {
1447       clutter_actor_unmap (iter);
1448     }
1449
1450   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1451
1452   /* clear the contents of the last paint volume, so that hiding + moving +
1453    * showing will not result in the wrong area being repainted
1454    */
1455   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1456   priv->last_paint_volume_valid = TRUE;
1457
1458   /* notify on parent mapped after potentially unmapping
1459    * children, so apps see a bottom-up notification.
1460    */
1461   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1462
1463   /* relinquish keyboard focus if we were unmapped while owning it */
1464   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1465     {
1466       ClutterStage *stage;
1467
1468       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1469
1470       if (stage != NULL)
1471         _clutter_stage_release_pick_id (stage, priv->pick_id);
1472
1473       priv->pick_id = -1;
1474
1475       if (stage != NULL &&
1476           clutter_stage_get_key_focus (stage) == self)
1477         {
1478           clutter_stage_set_key_focus (stage, NULL);
1479         }
1480     }
1481 }
1482
1483 /**
1484  * clutter_actor_unmap:
1485  * @self: A #ClutterActor
1486  *
1487  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1488  * unmaps its children if they were mapped.
1489  *
1490  * Calling this function is not encouraged: the default #ClutterActor
1491  * implementation of #ClutterActorClass.unmap() will also unmap any
1492  * eventual children by default when their parent is unmapped.
1493  *
1494  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1495  * chain up to the parent implementation.
1496  *
1497  * <note>It is important to note that the implementation of the
1498  * #ClutterActorClass.unmap() virtual function may be called after
1499  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1500  * implementation, but it is guaranteed to be called before the
1501  * #GObjectClass.finalize() implementation.</note>
1502  *
1503  * Since: 1.0
1504  */
1505 void
1506 clutter_actor_unmap (ClutterActor *self)
1507 {
1508   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1509
1510   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1511     return;
1512
1513   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1514 }
1515
1516 static void
1517 clutter_actor_real_show (ClutterActor *self)
1518 {
1519   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1520     {
1521       ClutterActorPrivate *priv = self->priv;
1522
1523       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1524
1525       /* we notify on the "visible" flag in the clutter_actor_show()
1526        * wrapper so the entire show signal emission completes first
1527        * (?)
1528        */
1529       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1530
1531       /* we queue a relayout unless the actor is inside a
1532        * container that explicitly told us not to
1533        */
1534       if (priv->parent != NULL &&
1535           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1536         {
1537           /* While an actor is hidden the parent may not have
1538            * allocated/requested so we need to start from scratch
1539            * and avoid the short-circuiting in
1540            * clutter_actor_queue_relayout().
1541            */
1542           priv->needs_width_request  = FALSE;
1543           priv->needs_height_request = FALSE;
1544           priv->needs_allocation     = FALSE;
1545           clutter_actor_queue_relayout (self);
1546         }
1547     }
1548 }
1549
1550 static inline void
1551 set_show_on_set_parent (ClutterActor *self,
1552                         gboolean      set_show)
1553 {
1554   ClutterActorPrivate *priv = self->priv;
1555
1556   set_show = !!set_show;
1557
1558   if (priv->show_on_set_parent == set_show)
1559     return;
1560
1561   if (priv->parent == NULL)
1562     {
1563       priv->show_on_set_parent = set_show;
1564       g_object_notify_by_pspec (G_OBJECT (self),
1565                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1566     }
1567 }
1568
1569 /**
1570  * clutter_actor_show:
1571  * @self: A #ClutterActor
1572  *
1573  * Flags an actor to be displayed. An actor that isn't shown will not
1574  * be rendered on the stage.
1575  *
1576  * Actors are visible by default.
1577  *
1578  * If this function is called on an actor without a parent, the
1579  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1580  * effect.
1581  */
1582 void
1583 clutter_actor_show (ClutterActor *self)
1584 {
1585   ClutterActorPrivate *priv;
1586
1587   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1588
1589   /* simple optimization */
1590   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1591     {
1592       /* we still need to set the :show-on-set-parent property, in
1593        * case show() is called on an unparented actor
1594        */
1595       set_show_on_set_parent (self, TRUE);
1596       return;
1597     }
1598
1599 #ifdef CLUTTER_ENABLE_DEBUG
1600   clutter_actor_verify_map_state (self);
1601 #endif
1602
1603   priv = self->priv;
1604
1605   g_object_freeze_notify (G_OBJECT (self));
1606
1607   set_show_on_set_parent (self, TRUE);
1608
1609   g_signal_emit (self, actor_signals[SHOW], 0);
1610   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1611
1612   if (priv->parent != NULL)
1613     clutter_actor_queue_redraw (priv->parent);
1614
1615   g_object_thaw_notify (G_OBJECT (self));
1616 }
1617
1618 /**
1619  * clutter_actor_show_all:
1620  * @self: a #ClutterActor
1621  *
1622  * Calls clutter_actor_show() on all children of an actor (if any).
1623  *
1624  * Since: 0.2
1625  *
1626  * Deprecated: 1.10: Actors are visible by default
1627  */
1628 void
1629 clutter_actor_show_all (ClutterActor *self)
1630 {
1631   ClutterActorClass *klass;
1632
1633   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1634
1635   klass = CLUTTER_ACTOR_GET_CLASS (self);
1636   if (klass->show_all)
1637     klass->show_all (self);
1638 }
1639
1640 static void
1641 clutter_actor_real_hide (ClutterActor *self)
1642 {
1643   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1644     {
1645       ClutterActorPrivate *priv = self->priv;
1646
1647       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1648
1649       /* we notify on the "visible" flag in the clutter_actor_hide()
1650        * wrapper so the entire hide signal emission completes first
1651        * (?)
1652        */
1653       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1654
1655       /* we queue a relayout unless the actor is inside a
1656        * container that explicitly told us not to
1657        */
1658       if (priv->parent != NULL &&
1659           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1660         clutter_actor_queue_relayout (priv->parent);
1661     }
1662 }
1663
1664 /**
1665  * clutter_actor_hide:
1666  * @self: A #ClutterActor
1667  *
1668  * Flags an actor to be hidden. A hidden actor will not be
1669  * rendered on the stage.
1670  *
1671  * Actors are visible by default.
1672  *
1673  * If this function is called on an actor without a parent, the
1674  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1675  * as a side-effect.
1676  */
1677 void
1678 clutter_actor_hide (ClutterActor *self)
1679 {
1680   ClutterActorPrivate *priv;
1681
1682   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1683
1684   /* simple optimization */
1685   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1686     {
1687       /* we still need to set the :show-on-set-parent property, in
1688        * case hide() is called on an unparented actor
1689        */
1690       set_show_on_set_parent (self, FALSE);
1691       return;
1692     }
1693
1694 #ifdef CLUTTER_ENABLE_DEBUG
1695   clutter_actor_verify_map_state (self);
1696 #endif
1697
1698   priv = self->priv;
1699
1700   g_object_freeze_notify (G_OBJECT (self));
1701
1702   set_show_on_set_parent (self, FALSE);
1703
1704   g_signal_emit (self, actor_signals[HIDE], 0);
1705   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1706
1707   if (priv->parent != NULL)
1708     clutter_actor_queue_redraw (priv->parent);
1709
1710   g_object_thaw_notify (G_OBJECT (self));
1711 }
1712
1713 /**
1714  * clutter_actor_hide_all:
1715  * @self: a #ClutterActor
1716  *
1717  * Calls clutter_actor_hide() on all child actors (if any).
1718  *
1719  * Since: 0.2
1720  *
1721  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1722  *   prevent its children from being painted as well.
1723  */
1724 void
1725 clutter_actor_hide_all (ClutterActor *self)
1726 {
1727   ClutterActorClass *klass;
1728
1729   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1730
1731   klass = CLUTTER_ACTOR_GET_CLASS (self);
1732   if (klass->hide_all)
1733     klass->hide_all (self);
1734 }
1735
1736 /**
1737  * clutter_actor_realize:
1738  * @self: A #ClutterActor
1739  *
1740  * Realization informs the actor that it is attached to a stage. It
1741  * can use this to allocate resources if it wanted to delay allocation
1742  * until it would be rendered. However it is perfectly acceptable for
1743  * an actor to create resources before being realized because Clutter
1744  * only ever has a single rendering context so that actor is free to
1745  * be moved from one stage to another.
1746  *
1747  * This function does nothing if the actor is already realized.
1748  *
1749  * Because a realized actor must have realized parent actors, calling
1750  * clutter_actor_realize() will also realize all parents of the actor.
1751  *
1752  * This function does not realize child actors, except in the special
1753  * case that realizing the stage, when the stage is visible, will
1754  * suddenly map (and thus realize) the children of the stage.
1755  **/
1756 void
1757 clutter_actor_realize (ClutterActor *self)
1758 {
1759   ClutterActorPrivate *priv;
1760
1761   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1762
1763   priv = self->priv;
1764
1765 #ifdef CLUTTER_ENABLE_DEBUG
1766   clutter_actor_verify_map_state (self);
1767 #endif
1768
1769   if (CLUTTER_ACTOR_IS_REALIZED (self))
1770     return;
1771
1772   /* To be realized, our parent actors must be realized first.
1773    * This will only succeed if we're inside a toplevel.
1774    */
1775   if (priv->parent != NULL)
1776     clutter_actor_realize (priv->parent);
1777
1778   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1779     {
1780       /* toplevels can be realized at any time */
1781     }
1782   else
1783     {
1784       /* "Fail" the realization if parent is missing or unrealized;
1785        * this should really be a g_warning() not some kind of runtime
1786        * failure; how can an app possibly recover? Instead it's a bug
1787        * in the app and the app should get an explanatory warning so
1788        * someone can fix it. But for now it's too hard to fix this
1789        * because e.g. ClutterTexture needs reworking.
1790        */
1791       if (priv->parent == NULL ||
1792           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1793         return;
1794     }
1795
1796   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1797
1798   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1799   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1800
1801   g_signal_emit (self, actor_signals[REALIZE], 0);
1802
1803   /* Stage actor is allowed to unset the realized flag again in its
1804    * default signal handler, though that is a pathological situation.
1805    */
1806
1807   /* If realization "failed" we'll have to update child state. */
1808   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1809 }
1810
1811 static void
1812 clutter_actor_real_unrealize (ClutterActor *self)
1813 {
1814   /* we must be unmapped (implying our children are also unmapped) */
1815   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1816 }
1817
1818 /**
1819  * clutter_actor_unrealize:
1820  * @self: A #ClutterActor
1821  *
1822  * Unrealization informs the actor that it may be being destroyed or
1823  * moved to another stage. The actor may want to destroy any
1824  * underlying graphics resources at this point. However it is
1825  * perfectly acceptable for it to retain the resources until the actor
1826  * is destroyed because Clutter only ever uses a single rendering
1827  * context and all of the graphics resources are valid on any stage.
1828  *
1829  * Because mapped actors must be realized, actors may not be
1830  * unrealized if they are mapped. This function hides the actor to be
1831  * sure it isn't mapped, an application-visible side effect that you
1832  * may not be expecting.
1833  *
1834  * This function should not be called by application code.
1835  */
1836 void
1837 clutter_actor_unrealize (ClutterActor *self)
1838 {
1839   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1840   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1841
1842 /* This function should not really be in the public API, because
1843  * there isn't a good reason to call it. ClutterActor will already
1844  * unrealize things for you when it's important to do so.
1845  *
1846  * If you were using clutter_actor_unrealize() in a dispose
1847  * implementation, then don't, just chain up to ClutterActor's
1848  * dispose.
1849  *
1850  * If you were using clutter_actor_unrealize() to implement
1851  * unrealizing children of your container, then don't, ClutterActor
1852  * will already take care of that.
1853  *
1854  * If you were using clutter_actor_unrealize() to re-realize to
1855  * create your resources in a different way, then use
1856  * _clutter_actor_rerealize() (inside Clutter) or just call your
1857  * code that recreates your resources directly (outside Clutter).
1858  */
1859
1860 #ifdef CLUTTER_ENABLE_DEBUG
1861   clutter_actor_verify_map_state (self);
1862 #endif
1863
1864   clutter_actor_hide (self);
1865
1866   clutter_actor_unrealize_not_hiding (self);
1867 }
1868
1869 static ClutterActorTraverseVisitFlags
1870 unrealize_actor_before_children_cb (ClutterActor *self,
1871                                     int depth,
1872                                     void *user_data)
1873 {
1874   /* If an actor is already unrealized we know its children have also
1875    * already been unrealized... */
1876   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1877     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1878
1879   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1880
1881   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1882 }
1883
1884 static ClutterActorTraverseVisitFlags
1885 unrealize_actor_after_children_cb (ClutterActor *self,
1886                                    int depth,
1887                                    void *user_data)
1888 {
1889   /* We want to unset the realized flag only _after_
1890    * child actors are unrealized, to maintain invariants.
1891    */
1892   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1893   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1894   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1895 }
1896
1897 /*
1898  * clutter_actor_unrealize_not_hiding:
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. You must hide the actor or one of
1910  * its parents before attempting to unrealize.
1911  *
1912  * This function is separate from clutter_actor_unrealize() because it
1913  * does not automatically hide the actor.
1914  * Actors need not be hidden to be unrealized, they just need to
1915  * be unmapped. In fact we don't want to mess up the application's
1916  * setting of the "visible" flag, so hiding is very undesirable.
1917  *
1918  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1919  * backward compatibility.
1920  */
1921 static void
1922 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1923 {
1924   _clutter_actor_traverse (self,
1925                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1926                            unrealize_actor_before_children_cb,
1927                            unrealize_actor_after_children_cb,
1928                            NULL);
1929 }
1930
1931 /*
1932  * _clutter_actor_rerealize:
1933  * @self: A #ClutterActor
1934  * @callback: Function to call while unrealized
1935  * @data: data for callback
1936  *
1937  * If an actor is already unrealized, this just calls the callback.
1938  *
1939  * If it is realized, it unrealizes temporarily, calls the callback,
1940  * and then re-realizes the actor.
1941  *
1942  * As a side effect, leaves all children of the actor unrealized if
1943  * the actor was realized but not showing.  This is because when we
1944  * unrealize the actor temporarily we must unrealize its children
1945  * (e.g. children of a stage can't be realized if stage window is
1946  * gone). And we aren't clever enough to save the realization state of
1947  * all children. In most cases this should not matter, because
1948  * the children will automatically realize when they next become mapped.
1949  */
1950 void
1951 _clutter_actor_rerealize (ClutterActor    *self,
1952                           ClutterCallback  callback,
1953                           void            *data)
1954 {
1955   gboolean was_mapped;
1956   gboolean was_showing;
1957   gboolean was_realized;
1958
1959   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1960
1961 #ifdef CLUTTER_ENABLE_DEBUG
1962   clutter_actor_verify_map_state (self);
1963 #endif
1964
1965   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1966   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1967   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1968
1969   /* Must be unmapped to unrealize. Note we only have to hide this
1970    * actor if it was mapped (if all parents were showing).  If actor
1971    * is merely visible (but not mapped), then that's fine, we can
1972    * leave it visible.
1973    */
1974   if (was_mapped)
1975     clutter_actor_hide (self);
1976
1977   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1978
1979   /* unrealize self and all children */
1980   clutter_actor_unrealize_not_hiding (self);
1981
1982   if (callback != NULL)
1983     {
1984       (* callback) (self, data);
1985     }
1986
1987   if (was_showing)
1988     clutter_actor_show (self); /* will realize only if mapping implies it */
1989   else if (was_realized)
1990     clutter_actor_realize (self); /* realize self and all parents */
1991 }
1992
1993 static void
1994 clutter_actor_real_pick (ClutterActor       *self,
1995                          const ClutterColor *color)
1996 {
1997   /* the default implementation is just to paint a rectangle
1998    * with the same size of the actor using the passed color
1999    */
2000   if (clutter_actor_should_pick_paint (self))
2001     {
2002       ClutterActorBox box = { 0, };
2003       float width, height;
2004
2005       clutter_actor_get_allocation_box (self, &box);
2006
2007       width = box.x2 - box.x1;
2008       height = box.y2 - box.y1;
2009
2010       cogl_set_source_color4ub (color->red,
2011                                 color->green,
2012                                 color->blue,
2013                                 color->alpha);
2014
2015       cogl_rectangle (0, 0, width, height);
2016     }
2017
2018   /* XXX - this thoroughly sucks, but we need to maintain compatibility
2019    * with existing container classes that override the pick() virtual
2020    * and chain up to the default implementation - otherwise we'll end up
2021    * painting our children twice.
2022    *
2023    * this has to go away for 2.0; hopefully along the pick() itself.
2024    */
2025   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2026     {
2027       ClutterActor *iter;
2028
2029       for (iter = self->priv->first_child;
2030            iter != NULL;
2031            iter = iter->priv->next_sibling)
2032         clutter_actor_paint (iter);
2033     }
2034 }
2035
2036 /**
2037  * clutter_actor_should_pick_paint:
2038  * @self: A #ClutterActor
2039  *
2040  * Should be called inside the implementation of the
2041  * #ClutterActor::pick virtual function in order to check whether
2042  * the actor should paint itself in pick mode or not.
2043  *
2044  * This function should never be called directly by applications.
2045  *
2046  * Return value: %TRUE if the actor should paint its silhouette,
2047  *   %FALSE otherwise
2048  */
2049 gboolean
2050 clutter_actor_should_pick_paint (ClutterActor *self)
2051 {
2052   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2053
2054   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2055       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2056        CLUTTER_ACTOR_IS_REACTIVE (self)))
2057     return TRUE;
2058
2059   return FALSE;
2060 }
2061
2062 static void
2063 clutter_actor_real_get_preferred_width (ClutterActor *self,
2064                                         gfloat        for_height,
2065                                         gfloat       *min_width_p,
2066                                         gfloat       *natural_width_p)
2067 {
2068   ClutterActorPrivate *priv = self->priv;
2069
2070   if (priv->n_children != 0 &&
2071       priv->layout_manager != NULL)
2072     {
2073       ClutterContainer *container = CLUTTER_CONTAINER (self);
2074
2075       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2076                     "for the preferred width",
2077                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2078                     priv->layout_manager);
2079
2080       clutter_layout_manager_get_preferred_width (priv->layout_manager,
2081                                                   container,
2082                                                   for_height,
2083                                                   min_width_p,
2084                                                   natural_width_p);
2085
2086       return;
2087     }
2088
2089   /* Default implementation is always 0x0, usually an actor
2090    * using this default is relying on someone to set the
2091    * request manually
2092    */
2093   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2094
2095   if (min_width_p)
2096     *min_width_p = 0;
2097
2098   if (natural_width_p)
2099     *natural_width_p = 0;
2100 }
2101
2102 static void
2103 clutter_actor_real_get_preferred_height (ClutterActor *self,
2104                                          gfloat        for_width,
2105                                          gfloat       *min_height_p,
2106                                          gfloat       *natural_height_p)
2107 {
2108   ClutterActorPrivate *priv = self->priv;
2109
2110   if (priv->n_children != 0 &&
2111       priv->layout_manager != NULL)
2112     {
2113       ClutterContainer *container = CLUTTER_CONTAINER (self);
2114
2115       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2116                     "for the preferred height",
2117                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2118                     priv->layout_manager);
2119
2120       clutter_layout_manager_get_preferred_height (priv->layout_manager,
2121                                                    container,
2122                                                    for_width,
2123                                                    min_height_p,
2124                                                    natural_height_p);
2125
2126       return;
2127     }
2128   /* Default implementation is always 0x0, usually an actor
2129    * using this default is relying on someone to set the
2130    * request manually
2131    */
2132   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2133
2134   if (min_height_p)
2135     *min_height_p = 0;
2136
2137   if (natural_height_p)
2138     *natural_height_p = 0;
2139 }
2140
2141 static void
2142 clutter_actor_store_old_geometry (ClutterActor    *self,
2143                                   ClutterActorBox *box)
2144 {
2145   *box = self->priv->allocation;
2146 }
2147
2148 static inline void
2149 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2150                                           const ClutterActorBox *old)
2151 {
2152   ClutterActorPrivate *priv = self->priv;
2153   GObject *obj = G_OBJECT (self);
2154
2155   g_object_freeze_notify (obj);
2156
2157   /* to avoid excessive requisition or allocation cycles we
2158    * use the cached values.
2159    *
2160    * - if we don't have an allocation we assume that we need
2161    *   to notify anyway
2162    * - if we don't have a width or a height request we notify
2163    *   width and height
2164    * - if we have a valid allocation then we check the old
2165    *   bounding box with the current allocation and we notify
2166    *   the changes
2167    */
2168   if (priv->needs_allocation)
2169     {
2170       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2171       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2172       g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2173       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2174       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2175       g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2176     }
2177   else if (priv->needs_width_request || priv->needs_height_request)
2178     {
2179       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2180       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2181       g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2182     }
2183   else
2184     {
2185       gfloat x, y;
2186       gfloat width, height;
2187
2188       x = priv->allocation.x1;
2189       y = priv->allocation.y1;
2190       width = priv->allocation.x2 - priv->allocation.x1;
2191       height = priv->allocation.y2 - priv->allocation.y1;
2192
2193       if (x != old->x1)
2194         {
2195           g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2196           g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2197         }
2198
2199       if (y != old->y1)
2200         {
2201           g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2202           g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2203         }
2204
2205       if (width != (old->x2 - old->x1))
2206         {
2207           g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2208           g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2209         }
2210
2211       if (height != (old->y2 - old->y1))
2212         {
2213           g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2214           g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2215         }
2216     }
2217
2218   g_object_thaw_notify (obj);
2219 }
2220
2221 /*< private >
2222  * clutter_actor_set_allocation_internal:
2223  * @self: a #ClutterActor
2224  * @box: a #ClutterActorBox
2225  * @flags: allocation flags
2226  *
2227  * Stores the allocation of @self.
2228  *
2229  * This function only performs basic storage and property notification.
2230  *
2231  * This function should be called by clutter_actor_set_allocation()
2232  * and by the default implementation of #ClutterActorClass.allocate().
2233  *
2234  * Return value: %TRUE if the allocation of the #ClutterActor has been
2235  *   changed, and %FALSE otherwise
2236  */
2237 static inline gboolean
2238 clutter_actor_set_allocation_internal (ClutterActor           *self,
2239                                        const ClutterActorBox  *box,
2240                                        ClutterAllocationFlags  flags)
2241 {
2242   ClutterActorPrivate *priv = self->priv;
2243   GObject *obj;
2244   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2245   gboolean flags_changed;
2246   gboolean retval;
2247   ClutterActorBox old_alloc = { 0, };
2248
2249   obj = G_OBJECT (self);
2250
2251   g_object_freeze_notify (obj);
2252
2253   clutter_actor_store_old_geometry (self, &old_alloc);
2254
2255   x1_changed = priv->allocation.x1 != box->x1;
2256   y1_changed = priv->allocation.y1 != box->y1;
2257   x2_changed = priv->allocation.x2 != box->x2;
2258   y2_changed = priv->allocation.y2 != box->y2;
2259
2260   flags_changed = priv->allocation_flags != flags;
2261
2262   priv->allocation = *box;
2263   priv->allocation_flags = flags;
2264
2265   /* allocation is authoritative */
2266   priv->needs_width_request = FALSE;
2267   priv->needs_height_request = FALSE;
2268   priv->needs_allocation = FALSE;
2269
2270   if (x1_changed || y1_changed ||
2271       x2_changed || y2_changed ||
2272       flags_changed)
2273     {
2274       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2275                     _clutter_actor_get_debug_name (self));
2276
2277       priv->transform_valid = FALSE;
2278
2279       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2280
2281       /* if the allocation changes, so does the content box */
2282       if (priv->content != NULL)
2283         {
2284           priv->content_box_valid = FALSE;
2285           g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2286         }
2287
2288       retval = TRUE;
2289     }
2290   else
2291     retval = FALSE;
2292
2293   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2294
2295   g_object_thaw_notify (obj);
2296
2297   return retval;
2298 }
2299
2300 static void clutter_actor_real_allocate (ClutterActor           *self,
2301                                          const ClutterActorBox  *box,
2302                                          ClutterAllocationFlags  flags);
2303
2304 static inline void
2305 clutter_actor_maybe_layout_children (ClutterActor           *self,
2306                                      const ClutterActorBox  *allocation,
2307                                      ClutterAllocationFlags  flags)
2308 {
2309   ClutterActorPrivate *priv = self->priv;
2310
2311   /* this is going to be a bit hard to follow, so let's put an explanation
2312    * here.
2313    *
2314    * we want ClutterActor to have a default layout manager if the actor was
2315    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2316    *
2317    * we also want any subclass of ClutterActor that does not override the
2318    * ::allocate() virtual function to delegate to a layout manager.
2319    *
2320    * finally, we want to allow people subclassing ClutterActor and overriding
2321    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2322    *
2323    * on the other hand, we want existing actor subclasses overriding the
2324    * ::allocate() virtual function and chaining up to the parent's
2325    * implementation to continue working without allocating their children
2326    * twice, or without entering an allocation loop.
2327    *
2328    * for the first two points, we check if the class of the actor is
2329    * overridding the ::allocate() virtual function; if it isn't, then we
2330    * follow through with checking whether we have children and a layout
2331    * manager, and eventually calling clutter_layout_manager_allocate().
2332    *
2333    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2334    * allocation flags that we got passed, and if it is present, we continue
2335    * with the check above.
2336    *
2337    * if neither of these two checks yields a positive result, we just
2338    * assume that the ::allocate() virtual function that resulted in this
2339    * function being called will also allocate the children of the actor.
2340    */
2341
2342   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2343     goto check_layout;
2344
2345   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2346     goto check_layout;
2347
2348   return;
2349
2350 check_layout:
2351   if (priv->n_children != 0 &&
2352       priv->layout_manager != NULL)
2353     {
2354       ClutterContainer *container = CLUTTER_CONTAINER (self);
2355       ClutterAllocationFlags children_flags;
2356       ClutterActorBox children_box;
2357
2358       /* normalize the box passed to the layout manager */
2359       children_box.x1 = children_box.y1 = 0.f;
2360       children_box.x2 = (allocation->x2 - allocation->x1);
2361       children_box.y2 = (allocation->y2 - allocation->y1);
2362
2363       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2364        * the actor's children, since it refers only to the current
2365        * actor's allocation.
2366        */
2367       children_flags = flags;
2368       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2369
2370       CLUTTER_NOTE (LAYOUT,
2371                     "Allocating %d children of %s "
2372                     "at { %.2f, %.2f - %.2f x %.2f } "
2373                     "using %s",
2374                     priv->n_children,
2375                     _clutter_actor_get_debug_name (self),
2376                     allocation->x1,
2377                     allocation->y1,
2378                     (allocation->x2 - allocation->x1),
2379                     (allocation->y2 - allocation->y1),
2380                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2381
2382       clutter_layout_manager_allocate (priv->layout_manager,
2383                                        container,
2384                                        &children_box,
2385                                        children_flags);
2386     }
2387 }
2388
2389 static void
2390 clutter_actor_real_allocate (ClutterActor           *self,
2391                              const ClutterActorBox  *box,
2392                              ClutterAllocationFlags  flags)
2393 {
2394   ClutterActorPrivate *priv = self->priv;
2395   gboolean changed;
2396
2397   g_object_freeze_notify (G_OBJECT (self));
2398
2399   changed = clutter_actor_set_allocation_internal (self, box, flags);
2400
2401   /* we allocate our children before we notify changes in our geometry,
2402    * so that people connecting to properties will be able to get valid
2403    * data out of the sub-tree of the scene graph that has this actor at
2404    * the root.
2405    */
2406   clutter_actor_maybe_layout_children (self, box, flags);
2407
2408   if (changed)
2409     {
2410       ClutterActorBox signal_box = priv->allocation;
2411       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2412
2413       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2414                      &signal_box,
2415                      signal_flags);
2416     }
2417
2418   g_object_thaw_notify (G_OBJECT (self));
2419 }
2420
2421 static void
2422 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2423                                     ClutterActor *origin)
2424 {
2425   /* no point in queuing a redraw on a destroyed actor */
2426   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2427     return;
2428
2429   /* NB: We can't bail out early here if the actor is hidden in case
2430    * the actor bas been cloned. In this case the clone will need to
2431    * receive the signal so it can queue its own redraw.
2432    */
2433
2434   /* calls klass->queue_redraw in default handler */
2435   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2436 }
2437
2438 static void
2439 clutter_actor_real_queue_redraw (ClutterActor *self,
2440                                  ClutterActor *origin)
2441 {
2442   ClutterActor *parent;
2443
2444   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2445                 _clutter_actor_get_debug_name (self),
2446                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2447                                : "same actor");
2448
2449   /* no point in queuing a redraw on a destroyed actor */
2450   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2451     return;
2452
2453   /* If the queue redraw is coming from a child then the actor has
2454      become dirty and any queued effect is no longer valid */
2455   if (self != origin)
2456     {
2457       self->priv->is_dirty = TRUE;
2458       self->priv->effect_to_redraw = NULL;
2459     }
2460
2461   /* If the actor isn't visible, we still had to emit the signal
2462    * to allow for a ClutterClone, but the appearance of the parent
2463    * won't change so we don't have to propagate up the hierarchy.
2464    */
2465   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2466     return;
2467
2468   /* Although we could determine here that a full stage redraw
2469    * has already been queued and immediately bail out, we actually
2470    * guarantee that we will propagate a queue-redraw signal to our
2471    * parent at least once so that it's possible to implement a
2472    * container that tracks which of its children have queued a
2473    * redraw.
2474    */
2475   if (self->priv->propagated_one_redraw)
2476     {
2477       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2478       if (stage != NULL &&
2479           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2480         return;
2481     }
2482
2483   self->priv->propagated_one_redraw = TRUE;
2484
2485   /* notify parents, if they are all visible eventually we'll
2486    * queue redraw on the stage, which queues the redraw idle.
2487    */
2488   parent = clutter_actor_get_parent (self);
2489   if (parent != NULL)
2490     {
2491       /* this will go up recursively */
2492       _clutter_actor_signal_queue_redraw (parent, origin);
2493     }
2494 }
2495
2496 static void
2497 clutter_actor_real_queue_relayout (ClutterActor *self)
2498 {
2499   ClutterActorPrivate *priv = self->priv;
2500
2501   /* no point in queueing a redraw on a destroyed actor */
2502   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2503     return;
2504
2505   priv->needs_width_request  = TRUE;
2506   priv->needs_height_request = TRUE;
2507   priv->needs_allocation     = TRUE;
2508
2509   /* reset the cached size requests */
2510   memset (priv->width_requests, 0,
2511           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2512   memset (priv->height_requests, 0,
2513           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2514
2515   /* We need to go all the way up the hierarchy */
2516   if (priv->parent != NULL)
2517     _clutter_actor_queue_only_relayout (priv->parent);
2518 }
2519
2520 /**
2521  * clutter_actor_apply_relative_transform_to_point:
2522  * @self: A #ClutterActor
2523  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2524  *   default #ClutterStage
2525  * @point: A point as #ClutterVertex
2526  * @vertex: (out caller-allocates): The translated #ClutterVertex
2527  *
2528  * Transforms @point in coordinates relative to the actor into
2529  * ancestor-relative coordinates using the relevant transform
2530  * stack (i.e. scale, rotation, etc).
2531  *
2532  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2533  * this case, the coordinates returned will be the coordinates on
2534  * the stage before the projection is applied. This is different from
2535  * the behaviour of clutter_actor_apply_transform_to_point().
2536  *
2537  * Since: 0.6
2538  */
2539 void
2540 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2541                                                  ClutterActor        *ancestor,
2542                                                  const ClutterVertex *point,
2543                                                  ClutterVertex       *vertex)
2544 {
2545   gfloat w;
2546   CoglMatrix matrix;
2547
2548   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2549   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2550   g_return_if_fail (point != NULL);
2551   g_return_if_fail (vertex != NULL);
2552
2553   *vertex = *point;
2554   w = 1.0;
2555
2556   if (ancestor == NULL)
2557     ancestor = _clutter_actor_get_stage_internal (self);
2558
2559   if (ancestor == NULL)
2560     {
2561       *vertex = *point;
2562       return;
2563     }
2564
2565   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2566   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2567 }
2568
2569 static gboolean
2570 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2571                                          const ClutterVertex *vertices_in,
2572                                          ClutterVertex *vertices_out,
2573                                          int n_vertices)
2574 {
2575   ClutterActor *stage;
2576   CoglMatrix modelview;
2577   CoglMatrix projection;
2578   float viewport[4];
2579
2580   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2581
2582   stage = _clutter_actor_get_stage_internal (self);
2583
2584   /* We really can't do anything meaningful in this case so don't try
2585    * to do any transform */
2586   if (stage == NULL)
2587     return FALSE;
2588
2589   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2590    * that gets us to stage coordinates, we want to go all the way to eye
2591    * coordinates */
2592   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2593
2594   /* Fetch the projection and viewport */
2595   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2596   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2597                                &viewport[0],
2598                                &viewport[1],
2599                                &viewport[2],
2600                                &viewport[3]);
2601
2602   _clutter_util_fully_transform_vertices (&modelview,
2603                                           &projection,
2604                                           viewport,
2605                                           vertices_in,
2606                                           vertices_out,
2607                                           n_vertices);
2608
2609   return TRUE;
2610 }
2611
2612 /**
2613  * clutter_actor_apply_transform_to_point:
2614  * @self: A #ClutterActor
2615  * @point: A point as #ClutterVertex
2616  * @vertex: (out caller-allocates): The translated #ClutterVertex
2617  *
2618  * Transforms @point in coordinates relative to the actor
2619  * into screen-relative coordinates with the current actor
2620  * transformation (i.e. scale, rotation, etc)
2621  *
2622  * Since: 0.4
2623  **/
2624 void
2625 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2626                                         const ClutterVertex *point,
2627                                         ClutterVertex       *vertex)
2628 {
2629   g_return_if_fail (point != NULL);
2630   g_return_if_fail (vertex != NULL);
2631   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2632 }
2633
2634 /*
2635  * _clutter_actor_get_relative_transformation_matrix:
2636  * @self: The actor whose coordinate space you want to transform from.
2637  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2638  *            or %NULL if you want to transform all the way to eye coordinates.
2639  * @matrix: A #CoglMatrix to store the transformation
2640  *
2641  * This gets a transformation @matrix that will transform coordinates from the
2642  * coordinate space of @self into the coordinate space of @ancestor.
2643  *
2644  * For example if you need a matrix that can transform the local actor
2645  * coordinates of @self into stage coordinates you would pass the actor's stage
2646  * pointer as the @ancestor.
2647  *
2648  * If you pass %NULL then the transformation will take you all the way through
2649  * to eye coordinates. This can be useful if you want to extract the entire
2650  * modelview transform that Clutter applies before applying the projection
2651  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2652  * using cogl_set_modelview_matrix() for example then you would want a matrix
2653  * that transforms into eye coordinates.
2654  *
2655  * <note><para>This function explicitly initializes the given @matrix. If you just
2656  * want clutter to multiply a relative transformation with an existing matrix
2657  * you can use clutter_actor_apply_relative_transformation_matrix()
2658  * instead.</para></note>
2659  *
2660  */
2661 /* XXX: We should consider caching the stage relative modelview along with
2662  * the actor itself */
2663 static void
2664 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2665                                                    ClutterActor *ancestor,
2666                                                    CoglMatrix *matrix)
2667 {
2668   cogl_matrix_init_identity (matrix);
2669
2670   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2671 }
2672
2673 /* Project the given @box into stage window coordinates, writing the
2674  * transformed vertices to @verts[]. */
2675 static gboolean
2676 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2677                                           const ClutterActorBox *box,
2678                                           ClutterVertex          verts[])
2679 {
2680   ClutterVertex box_vertices[4];
2681
2682   box_vertices[0].x = box->x1;
2683   box_vertices[0].y = box->y1;
2684   box_vertices[0].z = 0;
2685   box_vertices[1].x = box->x2;
2686   box_vertices[1].y = box->y1;
2687   box_vertices[1].z = 0;
2688   box_vertices[2].x = box->x1;
2689   box_vertices[2].y = box->y2;
2690   box_vertices[2].z = 0;
2691   box_vertices[3].x = box->x2;
2692   box_vertices[3].y = box->y2;
2693   box_vertices[3].z = 0;
2694
2695   return
2696     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2697 }
2698
2699 /**
2700  * clutter_actor_get_allocation_vertices:
2701  * @self: A #ClutterActor
2702  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2703  *   against, or %NULL to use the #ClutterStage
2704  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2705  *   location for an array of 4 #ClutterVertex in which to store the result
2706  *
2707  * Calculates the transformed coordinates of the four corners of the
2708  * actor in the plane of @ancestor. The returned vertices relate to
2709  * the #ClutterActorBox coordinates as follows:
2710  * <itemizedlist>
2711  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2712  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2713  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2714  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2715  * </itemizedlist>
2716  *
2717  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2718  * this case, the coordinates returned will be the coordinates on
2719  * the stage before the projection is applied. This is different from
2720  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2721  *
2722  * Since: 0.6
2723  */
2724 void
2725 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2726                                        ClutterActor  *ancestor,
2727                                        ClutterVertex  verts[])
2728 {
2729   ClutterActorPrivate *priv;
2730   ClutterActorBox box;
2731   ClutterVertex vertices[4];
2732   CoglMatrix modelview;
2733
2734   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2735   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2736
2737   if (ancestor == NULL)
2738     ancestor = _clutter_actor_get_stage_internal (self);
2739
2740   /* Fallback to a NOP transform if the actor isn't parented under a
2741    * stage. */
2742   if (ancestor == NULL)
2743     ancestor = self;
2744
2745   priv = self->priv;
2746
2747   /* if the actor needs to be allocated we force a relayout, so that
2748    * we will have valid values to use in the transformations */
2749   if (priv->needs_allocation)
2750     {
2751       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2752       if (stage)
2753         _clutter_stage_maybe_relayout (stage);
2754       else
2755         {
2756           box.x1 = box.y1 = 0;
2757           /* The result isn't really meaningful in this case but at
2758            * least try to do something *vaguely* reasonable... */
2759           clutter_actor_get_size (self, &box.x2, &box.y2);
2760         }
2761     }
2762
2763   clutter_actor_get_allocation_box (self, &box);
2764
2765   vertices[0].x = box.x1;
2766   vertices[0].y = box.y1;
2767   vertices[0].z = 0;
2768   vertices[1].x = box.x2;
2769   vertices[1].y = box.y1;
2770   vertices[1].z = 0;
2771   vertices[2].x = box.x1;
2772   vertices[2].y = box.y2;
2773   vertices[2].z = 0;
2774   vertices[3].x = box.x2;
2775   vertices[3].y = box.y2;
2776   vertices[3].z = 0;
2777
2778   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2779                                                      &modelview);
2780
2781   cogl_matrix_transform_points (&modelview,
2782                                 3,
2783                                 sizeof (ClutterVertex),
2784                                 vertices,
2785                                 sizeof (ClutterVertex),
2786                                 vertices,
2787                                 4);
2788 }
2789
2790 /**
2791  * clutter_actor_get_abs_allocation_vertices:
2792  * @self: A #ClutterActor
2793  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2794  *   of 4 #ClutterVertex where to store the result.
2795  *
2796  * Calculates the transformed screen coordinates of the four corners of
2797  * the actor; the returned vertices relate to the #ClutterActorBox
2798  * coordinates  as follows:
2799  * <itemizedlist>
2800  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2801  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2802  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2803  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2804  * </itemizedlist>
2805  *
2806  * Since: 0.4
2807  */
2808 void
2809 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2810                                            ClutterVertex  verts[])
2811 {
2812   ClutterActorPrivate *priv;
2813   ClutterActorBox actor_space_allocation;
2814
2815   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2816
2817   priv = self->priv;
2818
2819   /* if the actor needs to be allocated we force a relayout, so that
2820    * the actor allocation box will be valid for
2821    * _clutter_actor_transform_and_project_box()
2822    */
2823   if (priv->needs_allocation)
2824     {
2825       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2826       /* There's nothing meaningful we can do now */
2827       if (!stage)
2828         return;
2829
2830       _clutter_stage_maybe_relayout (stage);
2831     }
2832
2833   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2834    * own coordinate space... */
2835   actor_space_allocation.x1 = 0;
2836   actor_space_allocation.y1 = 0;
2837   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2838   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2839   _clutter_actor_transform_and_project_box (self,
2840                                             &actor_space_allocation,
2841                                             verts);
2842 }
2843
2844 static void
2845 clutter_actor_real_apply_transform (ClutterActor *self,
2846                                     CoglMatrix   *matrix)
2847 {
2848   ClutterActorPrivate *priv = self->priv;
2849
2850   if (!priv->transform_valid)
2851     {
2852       CoglMatrix *transform = &priv->transform;
2853       const ClutterTransformInfo *info;
2854
2855       info = _clutter_actor_get_transform_info_or_defaults (self);
2856
2857       cogl_matrix_init_identity (transform);
2858
2859       cogl_matrix_translate (transform,
2860                              priv->allocation.x1,
2861                              priv->allocation.y1,
2862                              0.0);
2863
2864       if (info->depth)
2865         cogl_matrix_translate (transform, 0, 0, info->depth);
2866
2867       /*
2868        * because the rotation involves translations, we must scale
2869        * before applying the rotations (if we apply the scale after
2870        * the rotations, the translations included in the rotation are
2871        * not scaled and so the entire object will move on the screen
2872        * as a result of rotating it).
2873        */
2874       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2875         {
2876           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2877                                         &info->scale_center,
2878                                         cogl_matrix_scale (transform,
2879                                                            info->scale_x,
2880                                                            info->scale_y,
2881                                                            1.0));
2882         }
2883
2884       if (info->rz_angle)
2885         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2886                                       &info->rz_center,
2887                                       cogl_matrix_rotate (transform,
2888                                                           info->rz_angle,
2889                                                           0, 0, 1.0));
2890
2891       if (info->ry_angle)
2892         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2893                                       &info->ry_center,
2894                                       cogl_matrix_rotate (transform,
2895                                                           info->ry_angle,
2896                                                           0, 1.0, 0));
2897
2898       if (info->rx_angle)
2899         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2900                                       &info->rx_center,
2901                                       cogl_matrix_rotate (transform,
2902                                                           info->rx_angle,
2903                                                           1.0, 0, 0));
2904
2905       if (!clutter_anchor_coord_is_zero (&info->anchor))
2906         {
2907           gfloat x, y, z;
2908
2909           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2910           cogl_matrix_translate (transform, -x, -y, -z);
2911         }
2912
2913       priv->transform_valid = TRUE;
2914     }
2915
2916   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2917 }
2918
2919 /* Applies the transforms associated with this actor to the given
2920  * matrix. */
2921 void
2922 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2923                                           CoglMatrix *matrix)
2924 {
2925   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2926 }
2927
2928 /*
2929  * clutter_actor_apply_relative_transformation_matrix:
2930  * @self: The actor whose coordinate space you want to transform from.
2931  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2932  *            or %NULL if you want to transform all the way to eye coordinates.
2933  * @matrix: A #CoglMatrix to apply the transformation too.
2934  *
2935  * This multiplies a transform with @matrix that will transform coordinates
2936  * from the coordinate space of @self into the coordinate space of @ancestor.
2937  *
2938  * For example if you need a matrix that can transform the local actor
2939  * coordinates of @self into stage coordinates you would pass the actor's stage
2940  * pointer as the @ancestor.
2941  *
2942  * If you pass %NULL then the transformation will take you all the way through
2943  * to eye coordinates. This can be useful if you want to extract the entire
2944  * modelview transform that Clutter applies before applying the projection
2945  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2946  * using cogl_set_modelview_matrix() for example then you would want a matrix
2947  * that transforms into eye coordinates.
2948  *
2949  * <note>This function doesn't initialize the given @matrix, it simply
2950  * multiplies the requested transformation matrix with the existing contents of
2951  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2952  * before calling this function, or you can use
2953  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2954  */
2955 void
2956 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2957                                                      ClutterActor *ancestor,
2958                                                      CoglMatrix *matrix)
2959 {
2960   ClutterActor *parent;
2961
2962   /* Note we terminate before ever calling stage->apply_transform()
2963    * since that would conceptually be relative to the underlying
2964    * window OpenGL coordinates so we'd need a special @ancestor
2965    * value to represent the fake parent of the stage. */
2966   if (self == ancestor)
2967     return;
2968
2969   parent = clutter_actor_get_parent (self);
2970
2971   if (parent != NULL)
2972     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2973                                                          matrix);
2974
2975   _clutter_actor_apply_modelview_transform (self, matrix);
2976 }
2977
2978 static void
2979 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2980                                        ClutterPaintVolume *pv,
2981                                        const char *label,
2982                                        const CoglColor *color)
2983 {
2984   static CoglPipeline *outline = NULL;
2985   CoglPrimitive *prim;
2986   ClutterVertex line_ends[12 * 2];
2987   int n_vertices;
2988   CoglContext *ctx =
2989     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2990   /* XXX: at some point we'll query this from the stage but we can't
2991    * do that until the osx backend uses Cogl natively. */
2992   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2993
2994   if (outline == NULL)
2995     outline = cogl_pipeline_new (ctx);
2996
2997   _clutter_paint_volume_complete (pv);
2998
2999   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
3000
3001   /* Front face */
3002   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3003   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3004   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3005   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3006
3007   if (!pv->is_2d)
3008     {
3009       /* Back face */
3010       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3011       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3012       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3013       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3014
3015       /* Lines connecting front face to back face */
3016       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3017       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3018       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3019       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3020     }
3021
3022   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3023                                 n_vertices,
3024                                 (CoglVertexP3 *)line_ends);
3025
3026   cogl_pipeline_set_color (outline, color);
3027   cogl_framebuffer_draw_primitive (fb, outline, prim);
3028   cogl_object_unref (prim);
3029
3030   if (label)
3031     {
3032       PangoLayout *layout;
3033       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3034       pango_layout_set_text (layout, label, -1);
3035       cogl_pango_render_layout (layout,
3036                                 pv->vertices[0].x,
3037                                 pv->vertices[0].y,
3038                                 color,
3039                                 0);
3040       g_object_unref (layout);
3041     }
3042 }
3043
3044 static void
3045 _clutter_actor_draw_paint_volume (ClutterActor *self)
3046 {
3047   ClutterPaintVolume *pv;
3048   CoglColor color;
3049
3050   pv = _clutter_actor_get_paint_volume_mutable (self);
3051   if (!pv)
3052     {
3053       gfloat width, height;
3054       ClutterPaintVolume fake_pv;
3055
3056       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3057       _clutter_paint_volume_init_static (&fake_pv, stage);
3058
3059       clutter_actor_get_size (self, &width, &height);
3060       clutter_paint_volume_set_width (&fake_pv, width);
3061       clutter_paint_volume_set_height (&fake_pv, height);
3062
3063       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3064       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3065                                              _clutter_actor_get_debug_name (self),
3066                                              &color);
3067
3068       clutter_paint_volume_free (&fake_pv);
3069     }
3070   else
3071     {
3072       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3073       _clutter_actor_draw_paint_volume_full (self, pv,
3074                                              _clutter_actor_get_debug_name (self),
3075                                              &color);
3076     }
3077 }
3078
3079 static void
3080 _clutter_actor_paint_cull_result (ClutterActor *self,
3081                                   gboolean success,
3082                                   ClutterCullResult result)
3083 {
3084   ClutterPaintVolume *pv;
3085   CoglColor color;
3086
3087   if (success)
3088     {
3089       if (result == CLUTTER_CULL_RESULT_IN)
3090         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3091       else if (result == CLUTTER_CULL_RESULT_OUT)
3092         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3093       else
3094         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3095     }
3096   else
3097     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3098
3099   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3100     _clutter_actor_draw_paint_volume_full (self, pv,
3101                                            _clutter_actor_get_debug_name (self),
3102                                            &color);
3103   else
3104     {
3105       PangoLayout *layout;
3106       char *label =
3107         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3108       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3109       cogl_set_source_color (&color);
3110
3111       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3112       pango_layout_set_text (layout, label, -1);
3113       cogl_pango_render_layout (layout,
3114                                 0,
3115                                 0,
3116                                 &color,
3117                                 0);
3118       g_free (label);
3119       g_object_unref (layout);
3120     }
3121 }
3122
3123 static int clone_paint_level = 0;
3124
3125 void
3126 _clutter_actor_push_clone_paint (void)
3127 {
3128   clone_paint_level++;
3129 }
3130
3131 void
3132 _clutter_actor_pop_clone_paint (void)
3133 {
3134   clone_paint_level--;
3135 }
3136
3137 static gboolean
3138 in_clone_paint (void)
3139 {
3140   return clone_paint_level > 0;
3141 }
3142
3143 /* Returns TRUE if the actor can be ignored */
3144 /* FIXME: we should return a ClutterCullResult, and
3145  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3146  * means there's no point in trying to cull descendants of the current
3147  * node. */
3148 static gboolean
3149 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3150 {
3151   ClutterActorPrivate *priv = self->priv;
3152   ClutterActor *stage;
3153   const ClutterPlane *stage_clip;
3154
3155   if (!priv->last_paint_volume_valid)
3156     {
3157       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3158                     "->last_paint_volume_valid == FALSE",
3159                     _clutter_actor_get_debug_name (self));
3160       return FALSE;
3161     }
3162
3163   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3164     return FALSE;
3165
3166   stage = _clutter_actor_get_stage_internal (self);
3167   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3168   if (G_UNLIKELY (!stage_clip))
3169     {
3170       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3171                     "No stage clip set",
3172                     _clutter_actor_get_debug_name (self));
3173       return FALSE;
3174     }
3175
3176   if (cogl_get_draw_framebuffer () !=
3177       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3178     {
3179       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3180                     "Current framebuffer doesn't correspond to stage",
3181                     _clutter_actor_get_debug_name (self));
3182       return FALSE;
3183     }
3184
3185   *result_out =
3186     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3187   return TRUE;
3188 }
3189
3190 static void
3191 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3192 {
3193   ClutterActorPrivate *priv = self->priv;
3194   const ClutterPaintVolume *pv;
3195
3196   if (priv->last_paint_volume_valid)
3197     {
3198       clutter_paint_volume_free (&priv->last_paint_volume);
3199       priv->last_paint_volume_valid = FALSE;
3200     }
3201
3202   pv = clutter_actor_get_paint_volume (self);
3203   if (!pv)
3204     {
3205       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3206                     "Actor failed to report a paint volume",
3207                     _clutter_actor_get_debug_name (self));
3208       return;
3209     }
3210
3211   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3212
3213   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3214                                             NULL); /* eye coordinates */
3215
3216   priv->last_paint_volume_valid = TRUE;
3217 }
3218
3219 static inline gboolean
3220 actor_has_shader_data (ClutterActor *self)
3221 {
3222   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3223 }
3224
3225 guint32
3226 _clutter_actor_get_pick_id (ClutterActor *self)
3227 {
3228   if (self->priv->pick_id < 0)
3229     return 0;
3230
3231   return self->priv->pick_id;
3232 }
3233
3234 /* This is the same as clutter_actor_add_effect except that it doesn't
3235    queue a redraw and it doesn't notify on the effect property */
3236 static void
3237 _clutter_actor_add_effect_internal (ClutterActor  *self,
3238                                     ClutterEffect *effect)
3239 {
3240   ClutterActorPrivate *priv = self->priv;
3241
3242   if (priv->effects == NULL)
3243     {
3244       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3245       priv->effects->actor = self;
3246     }
3247
3248   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3249 }
3250
3251 /* This is the same as clutter_actor_remove_effect except that it doesn't
3252    queue a redraw and it doesn't notify on the effect property */
3253 static void
3254 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3255                                        ClutterEffect *effect)
3256 {
3257   ClutterActorPrivate *priv = self->priv;
3258
3259   if (priv->effects == NULL)
3260     return;
3261
3262   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3263
3264   if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3265     g_clear_object (&priv->effects);
3266 }
3267
3268 static gboolean
3269 needs_flatten_effect (ClutterActor *self)
3270 {
3271   ClutterActorPrivate *priv = self->priv;
3272
3273   if (G_UNLIKELY (clutter_paint_debug_flags &
3274                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3275     return FALSE;
3276
3277   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3278     return TRUE;
3279   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3280     {
3281       if (clutter_actor_get_paint_opacity (self) < 255 &&
3282           clutter_actor_has_overlaps (self))
3283         return TRUE;
3284     }
3285
3286   return FALSE;
3287 }
3288
3289 static void
3290 add_or_remove_flatten_effect (ClutterActor *self)
3291 {
3292   ClutterActorPrivate *priv = self->priv;
3293
3294   /* Add or remove the flatten effect depending on the
3295      offscreen-redirect property. */
3296   if (needs_flatten_effect (self))
3297     {
3298       if (priv->flatten_effect == NULL)
3299         {
3300           ClutterActorMeta *actor_meta;
3301           gint priority;
3302
3303           priv->flatten_effect = _clutter_flatten_effect_new ();
3304           /* Keep a reference to the effect so that we can queue
3305              redraws from it */
3306           g_object_ref_sink (priv->flatten_effect);
3307
3308           /* Set the priority of the effect to high so that it will
3309              always be applied to the actor first. It uses an internal
3310              priority so that it won't be visible to applications */
3311           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3312           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3313           _clutter_actor_meta_set_priority (actor_meta, priority);
3314
3315           /* This will add the effect without queueing a redraw */
3316           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3317         }
3318     }
3319   else
3320     {
3321       if (priv->flatten_effect != NULL)
3322         {
3323           /* Destroy the effect so that it will lose its fbo cache of
3324              the actor */
3325           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3326           g_clear_object (&priv->flatten_effect);
3327         }
3328     }
3329 }
3330
3331 static void
3332 clutter_actor_real_paint (ClutterActor *actor)
3333 {
3334   ClutterActorPrivate *priv = actor->priv;
3335   ClutterActor *iter;
3336
3337   for (iter = priv->first_child;
3338        iter != NULL;
3339        iter = iter->priv->next_sibling)
3340     {
3341       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3342                     _clutter_actor_get_debug_name (iter),
3343                     _clutter_actor_get_debug_name (actor),
3344                     iter->priv->allocation.x1,
3345                     iter->priv->allocation.y1,
3346                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3347                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3348
3349       clutter_actor_paint (iter);
3350     }
3351 }
3352
3353 static gboolean
3354 clutter_actor_paint_node (ClutterActor     *actor,
3355                           ClutterPaintNode *root)
3356 {
3357   ClutterActorPrivate *priv = actor->priv;
3358
3359   if (root == NULL)
3360     return FALSE;
3361
3362   if (priv->bg_color_set &&
3363       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3364     {
3365       ClutterPaintNode *node;
3366       ClutterColor bg_color;
3367       ClutterActorBox box;
3368
3369       box.x1 = 0.f;
3370       box.y1 = 0.f;
3371       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3372       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3373
3374       bg_color = priv->bg_color;
3375       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3376                      * priv->bg_color.alpha
3377                      / 255;
3378
3379       node = clutter_color_node_new (&bg_color);
3380       clutter_paint_node_set_name (node, "backgroundColor");
3381       clutter_paint_node_add_rectangle (node, &box);
3382       clutter_paint_node_add_child (root, node);
3383       clutter_paint_node_unref (node);
3384     }
3385
3386   if (priv->content != NULL)
3387     _clutter_content_paint_content (priv->content, actor, root);
3388
3389   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3390     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3391
3392   if (clutter_paint_node_get_n_children (root) == 0)
3393     return FALSE;
3394
3395 #ifdef CLUTTER_ENABLE_DEBUG
3396   if (CLUTTER_HAS_DEBUG (PAINT))
3397     {
3398       /* dump the tree only if we have one */
3399       _clutter_paint_node_dump_tree (root);
3400     }
3401 #endif /* CLUTTER_ENABLE_DEBUG */
3402
3403   _clutter_paint_node_paint (root);
3404
3405 #if 0
3406   /* XXX: Uncomment this when we disable emitting the paint signal */
3407   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3408 #endif
3409
3410   return TRUE;
3411 }
3412
3413 /**
3414  * clutter_actor_paint:
3415  * @self: A #ClutterActor
3416  *
3417  * Renders the actor to display.
3418  *
3419  * This function should not be called directly by applications.
3420  * Call clutter_actor_queue_redraw() to queue paints, instead.
3421  *
3422  * This function is context-aware, and will either cause a
3423  * regular paint or a pick paint.
3424  *
3425  * This function will emit the #ClutterActor::paint signal or
3426  * the #ClutterActor::pick signal, depending on the context.
3427  *
3428  * This function does not paint the actor if the actor is set to 0,
3429  * unless it is performing a pick paint.
3430  */
3431 void
3432 clutter_actor_paint (ClutterActor *self)
3433 {
3434   ClutterActorPrivate *priv;
3435   ClutterPickMode pick_mode;
3436   gboolean clip_set = FALSE;
3437   gboolean shader_applied = FALSE;
3438
3439   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3440                           "Actor real-paint counter",
3441                           "Increments each time any actor is painted",
3442                           0 /* no application private data */);
3443   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3444                           "Actor pick-paint counter",
3445                           "Increments each time any actor is painted "
3446                           "for picking",
3447                           0 /* no application private data */);
3448
3449   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3450
3451   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3452     return;
3453
3454   priv = self->priv;
3455
3456   pick_mode = _clutter_context_get_pick_mode ();
3457
3458   if (pick_mode == CLUTTER_PICK_NONE)
3459     priv->propagated_one_redraw = FALSE;
3460
3461   /* It's an important optimization that we consider painting of
3462    * actors with 0 opacity to be a NOP... */
3463   if (pick_mode == CLUTTER_PICK_NONE &&
3464       /* ignore top-levels, since they might be transparent */
3465       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3466       /* Use the override opacity if its been set */
3467       ((priv->opacity_override >= 0) ?
3468        priv->opacity_override : priv->opacity) == 0)
3469     return;
3470
3471   /* if we aren't paintable (not in a toplevel with all
3472    * parents paintable) then do nothing.
3473    */
3474   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3475     return;
3476
3477   /* mark that we are in the paint process */
3478   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3479
3480   cogl_push_matrix();
3481
3482   if (priv->enable_model_view_transform)
3483     {
3484       CoglMatrix matrix;
3485
3486       /* XXX: It could be better to cache the modelview with the actor
3487        * instead of progressively building up the transformations on
3488        * the matrix stack every time we paint. */
3489       cogl_get_modelview_matrix (&matrix);
3490       _clutter_actor_apply_modelview_transform (self, &matrix);
3491
3492 #ifdef CLUTTER_ENABLE_DEBUG
3493       /* Catch when out-of-band transforms have been made by actors not as part
3494        * of an apply_transform vfunc... */
3495       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3496         {
3497           CoglMatrix expected_matrix;
3498
3499           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3500                                                              &expected_matrix);
3501
3502           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3503             {
3504               GString *buf = g_string_sized_new (1024);
3505               ClutterActor *parent;
3506
3507               parent = self;
3508               while (parent != NULL)
3509                 {
3510                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3511
3512                   if (parent->priv->parent != NULL)
3513                     g_string_append (buf, "->");
3514
3515                   parent = parent->priv->parent;
3516                 }
3517
3518               g_warning ("Unexpected transform found when painting actor "
3519                          "\"%s\". This will be caused by one of the actor's "
3520                          "ancestors (%s) using the Cogl API directly to transform "
3521                          "children instead of using ::apply_transform().",
3522                          _clutter_actor_get_debug_name (self),
3523                          buf->str);
3524
3525               g_string_free (buf, TRUE);
3526             }
3527         }
3528 #endif /* CLUTTER_ENABLE_DEBUG */
3529
3530       cogl_set_modelview_matrix (&matrix);
3531     }
3532
3533   if (priv->has_clip)
3534     {
3535       cogl_clip_push_rectangle (priv->clip.x,
3536                                 priv->clip.y,
3537                                 priv->clip.x + priv->clip.width,
3538                                 priv->clip.y + priv->clip.height);
3539       clip_set = TRUE;
3540     }
3541   else if (priv->clip_to_allocation)
3542     {
3543       gfloat width, height;
3544
3545       width  = priv->allocation.x2 - priv->allocation.x1;
3546       height = priv->allocation.y2 - priv->allocation.y1;
3547
3548       cogl_clip_push_rectangle (0, 0, width, height);
3549       clip_set = TRUE;
3550     }
3551
3552   if (pick_mode == CLUTTER_PICK_NONE)
3553     {
3554       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3555
3556       /* We check whether we need to add the flatten effect before
3557          each paint so that we can avoid having a mechanism for
3558          applications to notify when the value of the
3559          has_overlaps virtual changes. */
3560       add_or_remove_flatten_effect (self);
3561     }
3562   else
3563     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3564
3565   /* We save the current paint volume so that the next time the
3566    * actor queues a redraw we can constrain the redraw to just
3567    * cover the union of the new bounding box and the old.
3568    *
3569    * We also fetch the current paint volume to perform culling so
3570    * we can avoid painting actors outside the current clip region.
3571    *
3572    * If we are painting inside a clone, we should neither update
3573    * the paint volume or use it to cull painting, since the paint
3574    * box represents the location of the source actor on the
3575    * screen.
3576    *
3577    * XXX: We are starting to do a lot of vertex transforms on
3578    * the CPU in a typical paint, so at some point we should
3579    * audit these and consider caching some things.
3580    *
3581    * NB: We don't perform culling while picking at this point because
3582    * clutter-stage.c doesn't setup the clipping planes appropriately.
3583    *
3584    * NB: We don't want to update the last-paint-volume during picking
3585    * because the last-paint-volume is used to determine the old screen
3586    * space location of an actor that has moved so we can know the
3587    * minimal region to redraw to clear an old view of the actor. If we
3588    * update this during picking then by the time we come around to
3589    * paint then the last-paint-volume would likely represent the new
3590    * actor position not the old.
3591    */
3592   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3593     {
3594       gboolean success;
3595       /* annoyingly gcc warns if uninitialized even though
3596        * the initialization is redundant :-( */
3597       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3598
3599       if (G_LIKELY ((clutter_paint_debug_flags &
3600                      (CLUTTER_DEBUG_DISABLE_CULLING |
3601                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3602                     (CLUTTER_DEBUG_DISABLE_CULLING |
3603                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3604         _clutter_actor_update_last_paint_volume (self);
3605
3606       success = cull_actor (self, &result);
3607
3608       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3609         _clutter_actor_paint_cull_result (self, success, result);
3610       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3611         goto done;
3612     }
3613
3614   if (priv->effects == NULL)
3615     {
3616       if (pick_mode == CLUTTER_PICK_NONE &&
3617           actor_has_shader_data (self))
3618         {
3619           _clutter_actor_shader_pre_paint (self, FALSE);
3620           shader_applied = TRUE;
3621         }
3622
3623       priv->next_effect_to_paint = NULL;
3624     }
3625   else
3626     priv->next_effect_to_paint =
3627       _clutter_meta_group_peek_metas (priv->effects);
3628
3629   clutter_actor_continue_paint (self);
3630
3631   if (shader_applied)
3632     _clutter_actor_shader_post_paint (self);
3633
3634   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3635                   pick_mode == CLUTTER_PICK_NONE))
3636     _clutter_actor_draw_paint_volume (self);
3637
3638 done:
3639   /* If we make it here then the actor has run through a complete
3640      paint run including all the effects so it's no longer dirty */
3641   if (pick_mode == CLUTTER_PICK_NONE)
3642     priv->is_dirty = FALSE;
3643
3644   if (clip_set)
3645     cogl_clip_pop();
3646
3647   cogl_pop_matrix();
3648
3649   /* paint sequence complete */
3650   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3651 }
3652
3653 /**
3654  * clutter_actor_continue_paint:
3655  * @self: A #ClutterActor
3656  *
3657  * Run the next stage of the paint sequence. This function should only
3658  * be called within the implementation of the ‘run’ virtual of a
3659  * #ClutterEffect. It will cause the run method of the next effect to
3660  * be applied, or it will paint the actual actor if the current effect
3661  * is the last effect in the chain.
3662  *
3663  * Since: 1.8
3664  */
3665 void
3666 clutter_actor_continue_paint (ClutterActor *self)
3667 {
3668   ClutterActorPrivate *priv;
3669
3670   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3671   /* This should only be called from with in the ‘run’ implementation
3672      of a ClutterEffect */
3673   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3674
3675   priv = self->priv;
3676
3677   /* Skip any effects that are disabled */
3678   while (priv->next_effect_to_paint &&
3679          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3680     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3681
3682   /* If this has come from the last effect then we'll just paint the
3683      actual actor */
3684   if (priv->next_effect_to_paint == NULL)
3685     {
3686       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3687         {
3688           ClutterPaintNode *dummy;
3689
3690           /* XXX - this will go away in 2.0, when we can get rid of this
3691            * stuff and switch to a pure retained render tree of PaintNodes
3692            * for the entire frame, starting from the Stage; the paint()
3693            * virtual function can then be called directly.
3694            */
3695           dummy = _clutter_dummy_node_new (self);
3696           clutter_paint_node_set_name (dummy, "Root");
3697
3698           /* XXX - for 1.12, we use the return value of paint_node() to
3699            * decide whether we should emit the ::paint signal.
3700            */
3701           clutter_actor_paint_node (self, dummy);
3702           clutter_paint_node_unref (dummy);
3703
3704           g_signal_emit (self, actor_signals[PAINT], 0);
3705         }
3706       else
3707         {
3708           ClutterColor col = { 0, };
3709
3710           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3711
3712           /* Actor will then paint silhouette of itself in supplied
3713            * color.  See clutter_stage_get_actor_at_pos() for where
3714            * picking is enabled.
3715            */
3716           g_signal_emit (self, actor_signals[PICK], 0, &col);
3717         }
3718     }
3719   else
3720     {
3721       ClutterEffect *old_current_effect;
3722       ClutterEffectPaintFlags run_flags = 0;
3723
3724       /* Cache the current effect so that we can put it back before
3725          returning */
3726       old_current_effect = priv->current_effect;
3727
3728       priv->current_effect = priv->next_effect_to_paint->data;
3729       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3730
3731       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3732         {
3733           if (priv->is_dirty)
3734             {
3735               /* If there's an effect queued with this redraw then all
3736                  effects up to that one will be considered dirty. It
3737                  is expected the queued effect will paint the cached
3738                  image and not call clutter_actor_continue_paint again
3739                  (although it should work ok if it does) */
3740               if (priv->effect_to_redraw == NULL ||
3741                   priv->current_effect != priv->effect_to_redraw)
3742                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3743             }
3744
3745           _clutter_effect_paint (priv->current_effect, run_flags);
3746         }
3747       else
3748         {
3749           /* We can't determine when an actor has been modified since
3750              its last pick so lets just assume it has always been
3751              modified */
3752           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3753
3754           _clutter_effect_pick (priv->current_effect, run_flags);
3755         }
3756
3757       priv->current_effect = old_current_effect;
3758     }
3759 }
3760
3761 static ClutterActorTraverseVisitFlags
3762 invalidate_queue_redraw_entry (ClutterActor *self,
3763                                int           depth,
3764                                gpointer      user_data)
3765 {
3766   ClutterActorPrivate *priv = self->priv;
3767
3768   if (priv->queue_redraw_entry != NULL)
3769     {
3770       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3771       priv->queue_redraw_entry = NULL;
3772     }
3773
3774   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3775 }
3776
3777 static inline void
3778 remove_child (ClutterActor *self,
3779               ClutterActor *child)
3780 {
3781   ClutterActor *prev_sibling, *next_sibling;
3782
3783   prev_sibling = child->priv->prev_sibling;
3784   next_sibling = child->priv->next_sibling;
3785
3786   if (prev_sibling != NULL)
3787     prev_sibling->priv->next_sibling = next_sibling;
3788
3789   if (next_sibling != NULL)
3790     next_sibling->priv->prev_sibling = prev_sibling;
3791
3792   if (self->priv->first_child == child)
3793     self->priv->first_child = next_sibling;
3794
3795   if (self->priv->last_child == child)
3796     self->priv->last_child = prev_sibling;
3797
3798   child->priv->parent = NULL;
3799   child->priv->prev_sibling = NULL;
3800   child->priv->next_sibling = NULL;
3801 }
3802
3803 typedef enum {
3804   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3805   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3806   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3807   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3808   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3809   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3810
3811   /* default flags for public API */
3812   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3813                                     REMOVE_CHILD_EMIT_PARENT_SET |
3814                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3815                                     REMOVE_CHILD_CHECK_STATE |
3816                                     REMOVE_CHILD_FLUSH_QUEUE |
3817                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3818
3819   /* flags for legacy/deprecated API */
3820   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3821                                     REMOVE_CHILD_FLUSH_QUEUE |
3822                                     REMOVE_CHILD_EMIT_PARENT_SET |
3823                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3824 } ClutterActorRemoveChildFlags;
3825
3826 /*< private >
3827  * clutter_actor_remove_child_internal:
3828  * @self: a #ClutterActor
3829  * @child: the child of @self that has to be removed
3830  * @flags: control the removal operations
3831  *
3832  * Removes @child from the list of children of @self.
3833  */
3834 static void
3835 clutter_actor_remove_child_internal (ClutterActor                 *self,
3836                                      ClutterActor                 *child,
3837                                      ClutterActorRemoveChildFlags  flags)
3838 {
3839   ClutterActor *old_first, *old_last;
3840   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3841   gboolean flush_queue;
3842   gboolean notify_first_last;
3843   gboolean was_mapped;
3844
3845   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3846   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3847   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3848   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3849   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3850   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3851
3852   g_object_freeze_notify (G_OBJECT (self));
3853
3854   if (destroy_meta)
3855     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3856
3857   if (check_state)
3858     {
3859       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3860
3861       /* we need to unrealize *before* we set parent_actor to NULL,
3862        * because in an unrealize method actors are dissociating from the
3863        * stage, which means they need to be able to
3864        * clutter_actor_get_stage().
3865        *
3866        * yhis should unmap and unrealize, unless we're reparenting.
3867        */
3868       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3869     }
3870   else
3871     was_mapped = FALSE;
3872
3873   if (flush_queue)
3874     {
3875       /* We take this opportunity to invalidate any queue redraw entry
3876        * associated with the actor and descendants since we won't be able to
3877        * determine the appropriate stage after this.
3878        *
3879        * we do this after we updated the mapped state because actors might
3880        * end up queueing redraws inside their mapped/unmapped virtual
3881        * functions, and if we invalidate the redraw entry we could end up
3882        * with an inconsistent state and weird memory corruption. see
3883        * bugs:
3884        *
3885        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3886        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3887        */
3888       _clutter_actor_traverse (child,
3889                                0,
3890                                invalidate_queue_redraw_entry,
3891                                NULL,
3892                                NULL);
3893     }
3894
3895   old_first = self->priv->first_child;
3896   old_last = self->priv->last_child;
3897
3898   remove_child (self, child);
3899
3900   self->priv->n_children -= 1;
3901
3902   self->priv->age += 1;
3903
3904   /* clutter_actor_reparent() will emit ::parent-set for us */
3905   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3906     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3907
3908   /* if the child was mapped then we need to relayout ourselves to account
3909    * for the removed child
3910    */
3911   if (was_mapped)
3912     clutter_actor_queue_relayout (self);
3913
3914   /* we need to emit the signal before dropping the reference */
3915   if (emit_actor_removed)
3916     g_signal_emit_by_name (self, "actor-removed", child);
3917
3918   if (notify_first_last)
3919     {
3920       if (old_first != self->priv->first_child)
3921         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3922
3923       if (old_last != self->priv->last_child)
3924         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3925     }
3926
3927   g_object_thaw_notify (G_OBJECT (self));
3928
3929   /* remove the reference we acquired in clutter_actor_add_child() */
3930   g_object_unref (child);
3931 }
3932
3933 static const ClutterTransformInfo default_transform_info = {
3934   0.0, { 0, },          /* rotation-x */
3935   0.0, { 0, },          /* rotation-y */
3936   0.0, { 0, },          /* rotation-z */
3937
3938   1.0, 1.0, { 0, },     /* scale */
3939
3940   { 0, },               /* anchor */
3941
3942   0.0,                  /* depth */
3943 };
3944
3945 /*< private >
3946  * _clutter_actor_get_transform_info_or_defaults:
3947  * @self: a #ClutterActor
3948  *
3949  * Retrieves the ClutterTransformInfo structure associated to an actor.
3950  *
3951  * If the actor does not have a ClutterTransformInfo structure associated
3952  * to it, then the default structure will be returned.
3953  *
3954  * This function should only be used for getters.
3955  *
3956  * Return value: a const pointer to the ClutterTransformInfo structure
3957  */
3958 const ClutterTransformInfo *
3959 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3960 {
3961   ClutterTransformInfo *info;
3962
3963   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3964   if (info != NULL)
3965     return info;
3966
3967   return &default_transform_info;
3968 }
3969
3970 static void
3971 clutter_transform_info_free (gpointer data)
3972 {
3973   if (data != NULL)
3974     g_slice_free (ClutterTransformInfo, data);
3975 }
3976
3977 /*< private >
3978  * _clutter_actor_get_transform_info:
3979  * @self: a #ClutterActor
3980  *
3981  * Retrieves a pointer to the ClutterTransformInfo structure.
3982  *
3983  * If the actor does not have a ClutterTransformInfo associated to it, one
3984  * will be created and initialized to the default values.
3985  *
3986  * This function should be used for setters.
3987  *
3988  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3989  * instead.
3990  *
3991  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3992  *   structure
3993  */
3994 ClutterTransformInfo *
3995 _clutter_actor_get_transform_info (ClutterActor *self)
3996 {
3997   ClutterTransformInfo *info;
3998
3999   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
4000   if (info == NULL)
4001     {
4002       info = g_slice_new (ClutterTransformInfo);
4003
4004       *info = default_transform_info;
4005
4006       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4007                                info,
4008                                clutter_transform_info_free);
4009     }
4010
4011   return info;
4012 }
4013
4014 /*< private >
4015  * clutter_actor_set_rotation_angle_internal:
4016  * @self: a #ClutterActor
4017  * @axis: the axis of the angle to change
4018  * @angle: the angle of rotation
4019  *
4020  * Sets the rotation angle on the given axis without affecting the
4021  * rotation center point.
4022  */
4023 static inline void
4024 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
4025                                            ClutterRotateAxis  axis,
4026                                            gdouble            angle)
4027 {
4028   GObject *obj = G_OBJECT (self);
4029   ClutterTransformInfo *info;
4030
4031   info = _clutter_actor_get_transform_info (self);
4032
4033   g_object_freeze_notify (obj);
4034
4035   switch (axis)
4036     {
4037     case CLUTTER_X_AXIS:
4038       info->rx_angle = angle;
4039       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4040       break;
4041
4042     case CLUTTER_Y_AXIS:
4043       info->ry_angle = angle;
4044       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4045       break;
4046
4047     case CLUTTER_Z_AXIS:
4048       info->rz_angle = angle;
4049       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4050       break;
4051     }
4052
4053   self->priv->transform_valid = FALSE;
4054
4055   g_object_thaw_notify (obj);
4056
4057   clutter_actor_queue_redraw (self);
4058 }
4059
4060 static inline void
4061 clutter_actor_set_rotation_angle (ClutterActor      *self,
4062                                   ClutterRotateAxis  axis,
4063                                   gdouble            angle)
4064 {
4065   const ClutterTransformInfo *info;
4066   const double *cur_angle_p = NULL;
4067   GParamSpec *pspec = NULL;
4068
4069   info = _clutter_actor_get_transform_info_or_defaults (self);
4070
4071   switch (axis)
4072     {
4073     case CLUTTER_X_AXIS:
4074       cur_angle_p = &info->rx_angle;
4075       pspec = obj_props[PROP_ROTATION_ANGLE_X];
4076       break;
4077
4078     case CLUTTER_Y_AXIS:
4079       cur_angle_p = &info->ry_angle;
4080       pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4081       break;
4082
4083     case CLUTTER_Z_AXIS:
4084       cur_angle_p = &info->rz_angle;
4085       pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4086       break;
4087     }
4088
4089   g_assert (pspec != NULL);
4090   g_assert (cur_angle_p != NULL);
4091
4092   if (_clutter_actor_get_transition (self, pspec) == NULL)
4093     _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4094   else
4095     _clutter_actor_update_transition (self, pspec, angle);
4096
4097   clutter_actor_queue_redraw (self);
4098 }
4099
4100 /*< private >
4101  * clutter_actor_set_rotation_center_internal:
4102  * @self: a #ClutterActor
4103  * @axis: the axis of the center to change
4104  * @center: the coordinates of the rotation center
4105  *
4106  * Sets the rotation center on the given axis without affecting the
4107  * rotation angle.
4108  */
4109 static inline void
4110 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4111                                             ClutterRotateAxis    axis,
4112                                             const ClutterVertex *center)
4113 {
4114   GObject *obj = G_OBJECT (self);
4115   ClutterTransformInfo *info;
4116   ClutterVertex v = { 0, 0, 0 };
4117
4118   info = _clutter_actor_get_transform_info (self);
4119
4120   if (center != NULL)
4121     v = *center;
4122
4123   g_object_freeze_notify (obj);
4124
4125   switch (axis)
4126     {
4127     case CLUTTER_X_AXIS:
4128       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4129       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4130       break;
4131
4132     case CLUTTER_Y_AXIS:
4133       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4134       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4135       break;
4136
4137     case CLUTTER_Z_AXIS:
4138       /* if the previously set rotation center was fractional, then
4139        * setting explicit coordinates will have to notify the
4140        * :rotation-center-z-gravity property as well
4141        */
4142       if (info->rz_center.is_fractional)
4143         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4144
4145       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4146       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4147       break;
4148     }
4149
4150   self->priv->transform_valid = FALSE;
4151
4152   g_object_thaw_notify (obj);
4153
4154   clutter_actor_queue_redraw (self);
4155 }
4156
4157 static void
4158 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4159                                          double factor,
4160                                          GParamSpec *pspec)
4161 {
4162   GObject *obj = G_OBJECT (self);
4163   ClutterTransformInfo *info;
4164
4165   info = _clutter_actor_get_transform_info (self);
4166
4167   if (pspec == obj_props[PROP_SCALE_X])
4168     info->scale_x = factor;
4169   else
4170     info->scale_y = factor;
4171
4172   self->priv->transform_valid = FALSE;
4173   clutter_actor_queue_redraw (self);
4174   g_object_notify_by_pspec (obj, pspec);
4175 }
4176
4177 static inline void
4178 clutter_actor_set_scale_factor (ClutterActor      *self,
4179                                 ClutterRotateAxis  axis,
4180                                 gdouble            factor)
4181 {
4182   const ClutterTransformInfo *info;
4183   const double *scale_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       pspec = obj_props[PROP_SCALE_X];
4192       scale_p = &info->scale_x;
4193       break;
4194
4195     case CLUTTER_Y_AXIS:
4196       pspec = obj_props[PROP_SCALE_Y];
4197       scale_p = &info->scale_y;
4198       break;
4199
4200     case CLUTTER_Z_AXIS:
4201       break;
4202     }
4203
4204   g_assert (pspec != NULL);
4205   g_assert (scale_p != NULL);
4206
4207   if (_clutter_actor_get_transition (self, pspec) == NULL)
4208     _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4209   else
4210     _clutter_actor_update_transition (self, pspec, factor);
4211
4212   clutter_actor_queue_redraw (self);
4213 }
4214
4215 static inline void
4216 clutter_actor_set_scale_center (ClutterActor      *self,
4217                                 ClutterRotateAxis  axis,
4218                                 gfloat             coord)
4219 {
4220   GObject *obj = G_OBJECT (self);
4221   ClutterTransformInfo *info;
4222   gfloat center_x, center_y;
4223
4224   info = _clutter_actor_get_transform_info (self);
4225
4226   g_object_freeze_notify (obj);
4227
4228   /* get the current scale center coordinates */
4229   clutter_anchor_coord_get_units (self, &info->scale_center,
4230                                   &center_x,
4231                                   &center_y,
4232                                   NULL);
4233
4234   /* we need to notify this too, because setting explicit coordinates will
4235    * change the gravity as a side effect
4236    */
4237   if (info->scale_center.is_fractional)
4238     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4239
4240   switch (axis)
4241     {
4242     case CLUTTER_X_AXIS:
4243       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4244       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4245       break;
4246
4247     case CLUTTER_Y_AXIS:
4248       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4249       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4250       break;
4251
4252     default:
4253       g_assert_not_reached ();
4254     }
4255
4256   self->priv->transform_valid = FALSE;
4257
4258   clutter_actor_queue_redraw (self);
4259
4260   g_object_thaw_notify (obj);
4261 }
4262
4263 static inline void
4264 clutter_actor_set_scale_gravity (ClutterActor   *self,
4265                                  ClutterGravity  gravity)
4266 {
4267   ClutterTransformInfo *info;
4268   GObject *obj;
4269
4270   info = _clutter_actor_get_transform_info (self);
4271   obj = G_OBJECT (self);
4272
4273   if (gravity == CLUTTER_GRAVITY_NONE)
4274     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4275   else
4276     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4277
4278   self->priv->transform_valid = FALSE;
4279
4280   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4281   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4282   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4283
4284   clutter_actor_queue_redraw (self);
4285 }
4286
4287 static inline void
4288 clutter_actor_set_anchor_coord (ClutterActor      *self,
4289                                 ClutterRotateAxis  axis,
4290                                 gfloat             coord)
4291 {
4292   GObject *obj = G_OBJECT (self);
4293   ClutterTransformInfo *info;
4294   gfloat anchor_x, anchor_y;
4295
4296   info = _clutter_actor_get_transform_info (self);
4297
4298   g_object_freeze_notify (obj);
4299
4300   clutter_anchor_coord_get_units (self, &info->anchor,
4301                                   &anchor_x,
4302                                   &anchor_y,
4303                                   NULL);
4304
4305   if (info->anchor.is_fractional)
4306     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4307
4308   switch (axis)
4309     {
4310     case CLUTTER_X_AXIS:
4311       clutter_anchor_coord_set_units (&info->anchor,
4312                                       coord,
4313                                       anchor_y,
4314                                       0.0);
4315       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4316       break;
4317
4318     case CLUTTER_Y_AXIS:
4319       clutter_anchor_coord_set_units (&info->anchor,
4320                                       anchor_x,
4321                                       coord,
4322                                       0.0);
4323       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4324       break;
4325
4326     default:
4327       g_assert_not_reached ();
4328     }
4329
4330   self->priv->transform_valid = FALSE;
4331
4332   clutter_actor_queue_redraw (self);
4333
4334   g_object_thaw_notify (obj);
4335 }
4336
4337 static void
4338 clutter_actor_set_property (GObject      *object,
4339                             guint         prop_id,
4340                             const GValue *value,
4341                             GParamSpec   *pspec)
4342 {
4343   ClutterActor *actor = CLUTTER_ACTOR (object);
4344   ClutterActorPrivate *priv = actor->priv;
4345
4346   switch (prop_id)
4347     {
4348     case PROP_X:
4349       clutter_actor_set_x (actor, g_value_get_float (value));
4350       break;
4351
4352     case PROP_Y:
4353       clutter_actor_set_y (actor, g_value_get_float (value));
4354       break;
4355
4356     case PROP_POSITION:
4357       {
4358         const ClutterPoint *pos = g_value_get_boxed (value);
4359
4360         if (pos != NULL)
4361           clutter_actor_set_position (actor, pos->x, pos->y);
4362         else
4363           clutter_actor_set_fixed_position_set (actor, FALSE);
4364       }
4365       break;
4366
4367     case PROP_WIDTH:
4368       clutter_actor_set_width (actor, g_value_get_float (value));
4369       break;
4370
4371     case PROP_HEIGHT:
4372       clutter_actor_set_height (actor, g_value_get_float (value));
4373       break;
4374
4375     case PROP_SIZE:
4376       {
4377         const ClutterSize *size = g_value_get_boxed (value);
4378
4379         if (size != NULL)
4380           clutter_actor_set_size (actor, size->width, size->height);
4381         else
4382           clutter_actor_set_size (actor, -1, -1);
4383       }
4384       break;
4385
4386     case PROP_FIXED_X:
4387       clutter_actor_set_x (actor, g_value_get_float (value));
4388       break;
4389
4390     case PROP_FIXED_Y:
4391       clutter_actor_set_y (actor, g_value_get_float (value));
4392       break;
4393
4394     case PROP_FIXED_POSITION_SET:
4395       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4396       break;
4397
4398     case PROP_MIN_WIDTH:
4399       clutter_actor_set_min_width (actor, g_value_get_float (value));
4400       break;
4401
4402     case PROP_MIN_HEIGHT:
4403       clutter_actor_set_min_height (actor, g_value_get_float (value));
4404       break;
4405
4406     case PROP_NATURAL_WIDTH:
4407       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4408       break;
4409
4410     case PROP_NATURAL_HEIGHT:
4411       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4412       break;
4413
4414     case PROP_MIN_WIDTH_SET:
4415       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4416       break;
4417
4418     case PROP_MIN_HEIGHT_SET:
4419       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4420       break;
4421
4422     case PROP_NATURAL_WIDTH_SET:
4423       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4424       break;
4425
4426     case PROP_NATURAL_HEIGHT_SET:
4427       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4428       break;
4429
4430     case PROP_REQUEST_MODE:
4431       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4432       break;
4433
4434     case PROP_DEPTH:
4435       clutter_actor_set_depth (actor, g_value_get_float (value));
4436       break;
4437
4438     case PROP_OPACITY:
4439       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4440       break;
4441
4442     case PROP_OFFSCREEN_REDIRECT:
4443       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4444       break;
4445
4446     case PROP_NAME:
4447       clutter_actor_set_name (actor, g_value_get_string (value));
4448       break;
4449
4450     case PROP_VISIBLE:
4451       if (g_value_get_boolean (value) == TRUE)
4452         clutter_actor_show (actor);
4453       else
4454         clutter_actor_hide (actor);
4455       break;
4456
4457     case PROP_SCALE_X:
4458       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4459                                       g_value_get_double (value));
4460       break;
4461
4462     case PROP_SCALE_Y:
4463       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4464                                       g_value_get_double (value));
4465       break;
4466
4467     case PROP_SCALE_CENTER_X:
4468       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4469                                       g_value_get_float (value));
4470       break;
4471
4472     case PROP_SCALE_CENTER_Y:
4473       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4474                                       g_value_get_float (value));
4475       break;
4476
4477     case PROP_SCALE_GRAVITY:
4478       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4479       break;
4480
4481     case PROP_CLIP:
4482       {
4483         const ClutterGeometry *geom = g_value_get_boxed (value);
4484
4485         clutter_actor_set_clip (actor,
4486                                 geom->x, geom->y,
4487                                 geom->width, geom->height);
4488       }
4489       break;
4490
4491     case PROP_CLIP_TO_ALLOCATION:
4492       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4493       break;
4494
4495     case PROP_REACTIVE:
4496       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4497       break;
4498
4499     case PROP_ROTATION_ANGLE_X:
4500       clutter_actor_set_rotation_angle (actor,
4501                                         CLUTTER_X_AXIS,
4502                                         g_value_get_double (value));
4503       break;
4504
4505     case PROP_ROTATION_ANGLE_Y:
4506       clutter_actor_set_rotation_angle (actor,
4507                                         CLUTTER_Y_AXIS,
4508                                         g_value_get_double (value));
4509       break;
4510
4511     case PROP_ROTATION_ANGLE_Z:
4512       clutter_actor_set_rotation_angle (actor,
4513                                         CLUTTER_Z_AXIS,
4514                                         g_value_get_double (value));
4515       break;
4516
4517     case PROP_ROTATION_CENTER_X:
4518       clutter_actor_set_rotation_center_internal (actor,
4519                                                   CLUTTER_X_AXIS,
4520                                                   g_value_get_boxed (value));
4521       break;
4522
4523     case PROP_ROTATION_CENTER_Y:
4524       clutter_actor_set_rotation_center_internal (actor,
4525                                                   CLUTTER_Y_AXIS,
4526                                                   g_value_get_boxed (value));
4527       break;
4528
4529     case PROP_ROTATION_CENTER_Z:
4530       clutter_actor_set_rotation_center_internal (actor,
4531                                                   CLUTTER_Z_AXIS,
4532                                                   g_value_get_boxed (value));
4533       break;
4534
4535     case PROP_ROTATION_CENTER_Z_GRAVITY:
4536       {
4537         const ClutterTransformInfo *info;
4538
4539         info = _clutter_actor_get_transform_info_or_defaults (actor);
4540         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4541                                                    g_value_get_enum (value));
4542       }
4543       break;
4544
4545     case PROP_ANCHOR_X:
4546       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4547                                       g_value_get_float (value));
4548       break;
4549
4550     case PROP_ANCHOR_Y:
4551       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4552                                       g_value_get_float (value));
4553       break;
4554
4555     case PROP_ANCHOR_GRAVITY:
4556       clutter_actor_set_anchor_point_from_gravity (actor,
4557                                                    g_value_get_enum (value));
4558       break;
4559
4560     case PROP_SHOW_ON_SET_PARENT:
4561       priv->show_on_set_parent = g_value_get_boolean (value);
4562       break;
4563
4564     case PROP_TEXT_DIRECTION:
4565       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4566       break;
4567
4568     case PROP_ACTIONS:
4569       clutter_actor_add_action (actor, g_value_get_object (value));
4570       break;
4571
4572     case PROP_CONSTRAINTS:
4573       clutter_actor_add_constraint (actor, g_value_get_object (value));
4574       break;
4575
4576     case PROP_EFFECT:
4577       clutter_actor_add_effect (actor, g_value_get_object (value));
4578       break;
4579
4580     case PROP_LAYOUT_MANAGER:
4581       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4582       break;
4583
4584     case PROP_X_ALIGN:
4585       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4586       break;
4587
4588     case PROP_Y_ALIGN:
4589       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4590       break;
4591
4592     case PROP_MARGIN_TOP:
4593       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4594       break;
4595
4596     case PROP_MARGIN_BOTTOM:
4597       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4598       break;
4599
4600     case PROP_MARGIN_LEFT:
4601       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4602       break;
4603
4604     case PROP_MARGIN_RIGHT:
4605       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4606       break;
4607
4608     case PROP_BACKGROUND_COLOR:
4609       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4610       break;
4611
4612     case PROP_CONTENT:
4613       clutter_actor_set_content (actor, g_value_get_object (value));
4614       break;
4615
4616     case PROP_CONTENT_GRAVITY:
4617       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4618       break;
4619
4620     case PROP_MINIFICATION_FILTER:
4621       clutter_actor_set_content_scaling_filters (actor,
4622                                                  g_value_get_enum (value),
4623                                                  actor->priv->mag_filter);
4624       break;
4625
4626     case PROP_MAGNIFICATION_FILTER:
4627       clutter_actor_set_content_scaling_filters (actor,
4628                                                  actor->priv->min_filter,
4629                                                  g_value_get_enum (value));
4630       break;
4631
4632     default:
4633       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4634       break;
4635     }
4636 }
4637
4638 static void
4639 clutter_actor_get_property (GObject    *object,
4640                             guint       prop_id,
4641                             GValue     *value,
4642                             GParamSpec *pspec)
4643 {
4644   ClutterActor *actor = CLUTTER_ACTOR (object);
4645   ClutterActorPrivate *priv = actor->priv;
4646
4647   switch (prop_id)
4648     {
4649     case PROP_X:
4650       g_value_set_float (value, clutter_actor_get_x (actor));
4651       break;
4652
4653     case PROP_Y:
4654       g_value_set_float (value, clutter_actor_get_y (actor));
4655       break;
4656
4657     case PROP_POSITION:
4658       {
4659         ClutterPoint position;
4660
4661         clutter_point_init (&position,
4662                             clutter_actor_get_x (actor),
4663                             clutter_actor_get_y (actor));
4664         g_value_set_boxed (value, &position);
4665       }
4666       break;
4667
4668     case PROP_WIDTH:
4669       g_value_set_float (value, clutter_actor_get_width (actor));
4670       break;
4671
4672     case PROP_HEIGHT:
4673       g_value_set_float (value, clutter_actor_get_height (actor));
4674       break;
4675
4676     case PROP_SIZE:
4677       {
4678         ClutterSize size;
4679
4680         clutter_size_init (&size,
4681                            clutter_actor_get_width (actor),
4682                            clutter_actor_get_height (actor));
4683         g_value_set_boxed (value, &size);
4684       }
4685       break;
4686
4687     case PROP_FIXED_X:
4688       {
4689         const ClutterLayoutInfo *info;
4690
4691         info = _clutter_actor_get_layout_info_or_defaults (actor);
4692         g_value_set_float (value, info->fixed_pos.x);
4693       }
4694       break;
4695
4696     case PROP_FIXED_Y:
4697       {
4698         const ClutterLayoutInfo *info;
4699
4700         info = _clutter_actor_get_layout_info_or_defaults (actor);
4701         g_value_set_float (value, info->fixed_pos.y);
4702       }
4703       break;
4704
4705     case PROP_FIXED_POSITION_SET:
4706       g_value_set_boolean (value, priv->position_set);
4707       break;
4708
4709     case PROP_MIN_WIDTH:
4710       {
4711         const ClutterLayoutInfo *info;
4712
4713         info = _clutter_actor_get_layout_info_or_defaults (actor);
4714         g_value_set_float (value, info->minimum.width);
4715       }
4716       break;
4717
4718     case PROP_MIN_HEIGHT:
4719       {
4720         const ClutterLayoutInfo *info;
4721
4722         info = _clutter_actor_get_layout_info_or_defaults (actor);
4723         g_value_set_float (value, info->minimum.height);
4724       }
4725       break;
4726
4727     case PROP_NATURAL_WIDTH:
4728       {
4729         const ClutterLayoutInfo *info;
4730
4731         info = _clutter_actor_get_layout_info_or_defaults (actor);
4732         g_value_set_float (value, info->natural.width);
4733       }
4734       break;
4735
4736     case PROP_NATURAL_HEIGHT:
4737       {
4738         const ClutterLayoutInfo *info;
4739
4740         info = _clutter_actor_get_layout_info_or_defaults (actor);
4741         g_value_set_float (value, info->natural.height);
4742       }
4743       break;
4744
4745     case PROP_MIN_WIDTH_SET:
4746       g_value_set_boolean (value, priv->min_width_set);
4747       break;
4748
4749     case PROP_MIN_HEIGHT_SET:
4750       g_value_set_boolean (value, priv->min_height_set);
4751       break;
4752
4753     case PROP_NATURAL_WIDTH_SET:
4754       g_value_set_boolean (value, priv->natural_width_set);
4755       break;
4756
4757     case PROP_NATURAL_HEIGHT_SET:
4758       g_value_set_boolean (value, priv->natural_height_set);
4759       break;
4760
4761     case PROP_REQUEST_MODE:
4762       g_value_set_enum (value, priv->request_mode);
4763       break;
4764
4765     case PROP_ALLOCATION:
4766       g_value_set_boxed (value, &priv->allocation);
4767       break;
4768
4769     case PROP_DEPTH:
4770       g_value_set_float (value, clutter_actor_get_depth (actor));
4771       break;
4772
4773     case PROP_OPACITY:
4774       g_value_set_uint (value, priv->opacity);
4775       break;
4776
4777     case PROP_OFFSCREEN_REDIRECT:
4778       g_value_set_enum (value, priv->offscreen_redirect);
4779       break;
4780
4781     case PROP_NAME:
4782       g_value_set_string (value, priv->name);
4783       break;
4784
4785     case PROP_VISIBLE:
4786       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4787       break;
4788
4789     case PROP_MAPPED:
4790       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4791       break;
4792
4793     case PROP_REALIZED:
4794       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4795       break;
4796
4797     case PROP_HAS_CLIP:
4798       g_value_set_boolean (value, priv->has_clip);
4799       break;
4800
4801     case PROP_CLIP:
4802       {
4803         ClutterGeometry clip;
4804
4805         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4806         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4807         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4808         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4809
4810         g_value_set_boxed (value, &clip);
4811       }
4812       break;
4813
4814     case PROP_CLIP_TO_ALLOCATION:
4815       g_value_set_boolean (value, priv->clip_to_allocation);
4816       break;
4817
4818     case PROP_SCALE_X:
4819       {
4820         const ClutterTransformInfo *info;
4821
4822         info = _clutter_actor_get_transform_info_or_defaults (actor);
4823         g_value_set_double (value, info->scale_x);
4824       }
4825       break;
4826
4827     case PROP_SCALE_Y:
4828       {
4829         const ClutterTransformInfo *info;
4830
4831         info = _clutter_actor_get_transform_info_or_defaults (actor);
4832         g_value_set_double (value, info->scale_y);
4833       }
4834       break;
4835
4836     case PROP_SCALE_CENTER_X:
4837       {
4838         gfloat center;
4839
4840         clutter_actor_get_scale_center (actor, &center, NULL);
4841
4842         g_value_set_float (value, center);
4843       }
4844       break;
4845
4846     case PROP_SCALE_CENTER_Y:
4847       {
4848         gfloat center;
4849
4850         clutter_actor_get_scale_center (actor, NULL, &center);
4851
4852         g_value_set_float (value, center);
4853       }
4854       break;
4855
4856     case PROP_SCALE_GRAVITY:
4857       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4858       break;
4859
4860     case PROP_REACTIVE:
4861       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4862       break;
4863
4864     case PROP_ROTATION_ANGLE_X:
4865       {
4866         const ClutterTransformInfo *info;
4867
4868         info = _clutter_actor_get_transform_info_or_defaults (actor);
4869         g_value_set_double (value, info->rx_angle);
4870       }
4871       break;
4872
4873     case PROP_ROTATION_ANGLE_Y:
4874       {
4875         const ClutterTransformInfo *info;
4876
4877         info = _clutter_actor_get_transform_info_or_defaults (actor);
4878         g_value_set_double (value, info->ry_angle);
4879       }
4880       break;
4881
4882     case PROP_ROTATION_ANGLE_Z:
4883       {
4884         const ClutterTransformInfo *info;
4885
4886         info = _clutter_actor_get_transform_info_or_defaults (actor);
4887         g_value_set_double (value, info->rz_angle);
4888       }
4889       break;
4890
4891     case PROP_ROTATION_CENTER_X:
4892       {
4893         ClutterVertex center;
4894
4895         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4896                                     &center.x,
4897                                     &center.y,
4898                                     &center.z);
4899
4900         g_value_set_boxed (value, &center);
4901       }
4902       break;
4903
4904     case PROP_ROTATION_CENTER_Y:
4905       {
4906         ClutterVertex center;
4907
4908         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4909                                     &center.x,
4910                                     &center.y,
4911                                     &center.z);
4912
4913         g_value_set_boxed (value, &center);
4914       }
4915       break;
4916
4917     case PROP_ROTATION_CENTER_Z:
4918       {
4919         ClutterVertex center;
4920
4921         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4922                                     &center.x,
4923                                     &center.y,
4924                                     &center.z);
4925
4926         g_value_set_boxed (value, &center);
4927       }
4928       break;
4929
4930     case PROP_ROTATION_CENTER_Z_GRAVITY:
4931       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4932       break;
4933
4934     case PROP_ANCHOR_X:
4935       {
4936         const ClutterTransformInfo *info;
4937         gfloat anchor_x;
4938
4939         info = _clutter_actor_get_transform_info_or_defaults (actor);
4940         clutter_anchor_coord_get_units (actor, &info->anchor,
4941                                         &anchor_x,
4942                                         NULL,
4943                                         NULL);
4944         g_value_set_float (value, anchor_x);
4945       }
4946       break;
4947
4948     case PROP_ANCHOR_Y:
4949       {
4950         const ClutterTransformInfo *info;
4951         gfloat anchor_y;
4952
4953         info = _clutter_actor_get_transform_info_or_defaults (actor);
4954         clutter_anchor_coord_get_units (actor, &info->anchor,
4955                                         NULL,
4956                                         &anchor_y,
4957                                         NULL);
4958         g_value_set_float (value, anchor_y);
4959       }
4960       break;
4961
4962     case PROP_ANCHOR_GRAVITY:
4963       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4964       break;
4965
4966     case PROP_SHOW_ON_SET_PARENT:
4967       g_value_set_boolean (value, priv->show_on_set_parent);
4968       break;
4969
4970     case PROP_TEXT_DIRECTION:
4971       g_value_set_enum (value, priv->text_direction);
4972       break;
4973
4974     case PROP_HAS_POINTER:
4975       g_value_set_boolean (value, priv->has_pointer);
4976       break;
4977
4978     case PROP_LAYOUT_MANAGER:
4979       g_value_set_object (value, priv->layout_manager);
4980       break;
4981
4982     case PROP_X_ALIGN:
4983       {
4984         const ClutterLayoutInfo *info;
4985
4986         info = _clutter_actor_get_layout_info_or_defaults (actor);
4987         g_value_set_enum (value, info->x_align);
4988       }
4989       break;
4990
4991     case PROP_Y_ALIGN:
4992       {
4993         const ClutterLayoutInfo *info;
4994
4995         info = _clutter_actor_get_layout_info_or_defaults (actor);
4996         g_value_set_enum (value, info->y_align);
4997       }
4998       break;
4999
5000     case PROP_MARGIN_TOP:
5001       {
5002         const ClutterLayoutInfo *info;
5003
5004         info = _clutter_actor_get_layout_info_or_defaults (actor);
5005         g_value_set_float (value, info->margin.top);
5006       }
5007       break;
5008
5009     case PROP_MARGIN_BOTTOM:
5010       {
5011         const ClutterLayoutInfo *info;
5012
5013         info = _clutter_actor_get_layout_info_or_defaults (actor);
5014         g_value_set_float (value, info->margin.bottom);
5015       }
5016       break;
5017
5018     case PROP_MARGIN_LEFT:
5019       {
5020         const ClutterLayoutInfo *info;
5021
5022         info = _clutter_actor_get_layout_info_or_defaults (actor);
5023         g_value_set_float (value, info->margin.left);
5024       }
5025       break;
5026
5027     case PROP_MARGIN_RIGHT:
5028       {
5029         const ClutterLayoutInfo *info;
5030
5031         info = _clutter_actor_get_layout_info_or_defaults (actor);
5032         g_value_set_float (value, info->margin.right);
5033       }
5034       break;
5035
5036     case PROP_BACKGROUND_COLOR_SET:
5037       g_value_set_boolean (value, priv->bg_color_set);
5038       break;
5039
5040     case PROP_BACKGROUND_COLOR:
5041       g_value_set_boxed (value, &priv->bg_color);
5042       break;
5043
5044     case PROP_FIRST_CHILD:
5045       g_value_set_object (value, priv->first_child);
5046       break;
5047
5048     case PROP_LAST_CHILD:
5049       g_value_set_object (value, priv->last_child);
5050       break;
5051
5052     case PROP_CONTENT:
5053       g_value_set_object (value, priv->content);
5054       break;
5055
5056     case PROP_CONTENT_GRAVITY:
5057       g_value_set_enum (value, priv->content_gravity);
5058       break;
5059
5060     case PROP_CONTENT_BOX:
5061       {
5062         ClutterActorBox box = { 0, };
5063
5064         clutter_actor_get_content_box (actor, &box);
5065         g_value_set_boxed (value, &box);
5066       }
5067       break;
5068
5069     case PROP_MINIFICATION_FILTER:
5070       g_value_set_enum (value, priv->min_filter);
5071       break;
5072
5073     case PROP_MAGNIFICATION_FILTER:
5074       g_value_set_enum (value, priv->mag_filter);
5075       break;
5076
5077     default:
5078       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5079       break;
5080     }
5081 }
5082
5083 static void
5084 clutter_actor_dispose (GObject *object)
5085 {
5086   ClutterActor *self = CLUTTER_ACTOR (object);
5087   ClutterActorPrivate *priv = self->priv;
5088
5089   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5090                 priv->id,
5091                 g_type_name (G_OBJECT_TYPE (self)),
5092                 object->ref_count);
5093
5094   g_signal_emit (self, actor_signals[DESTROY], 0);
5095
5096   /* avoid recursing when called from clutter_actor_destroy() */
5097   if (priv->parent != NULL)
5098     {
5099       ClutterActor *parent = priv->parent;
5100
5101       /* go through the Container implementation unless this
5102        * is an internal child and has been marked as such.
5103        *
5104        * removing the actor from its parent will reset the
5105        * realized and mapped states.
5106        */
5107       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5108         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5109       else
5110         clutter_actor_remove_child_internal (parent, self,
5111                                              REMOVE_CHILD_LEGACY_FLAGS);
5112     }
5113
5114   /* parent must be gone at this point */
5115   g_assert (priv->parent == NULL);
5116
5117   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5118     {
5119       /* can't be mapped or realized with no parent */
5120       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5121       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5122     }
5123
5124   g_clear_object (&priv->pango_context);
5125   g_clear_object (&priv->actions);
5126   g_clear_object (&priv->constraints);
5127   g_clear_object (&priv->effects);
5128   g_clear_object (&priv->flatten_effect);
5129
5130   if (priv->layout_manager != NULL)
5131     {
5132       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5133       g_clear_object (&priv->layout_manager);
5134     }
5135
5136   if (priv->content != NULL)
5137     {
5138       _clutter_content_detached (priv->content, self);
5139       g_clear_object (&priv->content);
5140     }
5141
5142   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5143 }
5144
5145 static void
5146 clutter_actor_finalize (GObject *object)
5147 {
5148   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5149
5150   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5151                 priv->name != NULL ? priv->name : "<none>",
5152                 priv->id,
5153                 g_type_name (G_OBJECT_TYPE (object)));
5154
5155   _clutter_context_release_id (priv->id);
5156
5157   g_free (priv->name);
5158
5159   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5160 }
5161
5162
5163 /**
5164  * clutter_actor_get_accessible:
5165  * @self: a #ClutterActor
5166  *
5167  * Returns the accessible object that describes the actor to an
5168  * assistive technology.
5169  *
5170  * If no class-specific #AtkObject implementation is available for the
5171  * actor instance in question, it will inherit an #AtkObject
5172  * implementation from the first ancestor class for which such an
5173  * implementation is defined.
5174  *
5175  * The documentation of the <ulink
5176  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5177  * library contains more information about accessible objects and
5178  * their uses.
5179  *
5180  * Returns: (transfer none): the #AtkObject associated with @actor
5181  */
5182 AtkObject *
5183 clutter_actor_get_accessible (ClutterActor *self)
5184 {
5185   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5186
5187   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5188 }
5189
5190 static AtkObject *
5191 clutter_actor_real_get_accessible (ClutterActor *actor)
5192 {
5193   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5194 }
5195
5196 static AtkObject *
5197 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5198 {
5199   AtkObject *accessible;
5200
5201   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5202   if (accessible != NULL)
5203     g_object_ref (accessible);
5204
5205   return accessible;
5206 }
5207
5208 static void
5209 atk_implementor_iface_init (AtkImplementorIface *iface)
5210 {
5211   iface->ref_accessible = _clutter_actor_ref_accessible;
5212 }
5213
5214 static gboolean
5215 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5216                                            ClutterPaintVolume *volume)
5217 {
5218   ClutterActorPrivate *priv = self->priv;
5219   gboolean res = TRUE;
5220
5221   /* we start from the allocation */
5222   clutter_paint_volume_set_width (volume,
5223                                   priv->allocation.x2 - priv->allocation.x1);
5224   clutter_paint_volume_set_height (volume,
5225                                    priv->allocation.y2 - priv->allocation.y1);
5226
5227   /* if the actor has a clip set then we have a pretty definite
5228    * size for the paint volume: the actor cannot possibly paint
5229    * outside the clip region.
5230    */
5231   if (priv->clip_to_allocation)
5232     {
5233       /* the allocation has already been set, so we just flip the
5234        * return value
5235        */
5236       res = TRUE;
5237     }
5238   else
5239     {
5240       ClutterActor *child;
5241
5242       if (priv->has_clip &&
5243           priv->clip.width >= 0 &&
5244           priv->clip.height >= 0)
5245         {
5246           ClutterVertex origin;
5247
5248           origin.x = priv->clip.x;
5249           origin.y = priv->clip.y;
5250           origin.z = 0;
5251
5252           clutter_paint_volume_set_origin (volume, &origin);
5253           clutter_paint_volume_set_width (volume, priv->clip.width);
5254           clutter_paint_volume_set_height (volume, priv->clip.height);
5255
5256           res = TRUE;
5257         }
5258
5259       /* if we don't have children we just bail out here... */
5260       if (priv->n_children == 0)
5261         return res;
5262
5263       /* ...but if we have children then we ask for their paint volume in
5264        * our coordinates. if any of our children replies that it doesn't
5265        * have a paint volume, we bail out
5266        */
5267       for (child = priv->first_child;
5268            child != NULL;
5269            child = child->priv->next_sibling)
5270         {
5271           const ClutterPaintVolume *child_volume;
5272
5273           if (!CLUTTER_ACTOR_IS_MAPPED (child))
5274             continue;
5275
5276           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5277           if (child_volume == NULL)
5278             {
5279               res = FALSE;
5280               break;
5281             }
5282
5283           clutter_paint_volume_union (volume, child_volume);
5284           res = TRUE;
5285         }
5286     }
5287
5288   return res;
5289
5290 }
5291
5292 static gboolean
5293 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5294                                      ClutterPaintVolume *volume)
5295 {
5296   ClutterActorClass *klass;
5297   gboolean res;
5298
5299   klass = CLUTTER_ACTOR_GET_CLASS (self);
5300
5301   /* XXX - this thoroughly sucks, but we don't want to penalize users
5302    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5303    * redraw. This should go away in 2.0.
5304    */
5305   if (klass->paint == clutter_actor_real_paint &&
5306       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5307     {
5308       res = TRUE;
5309     }
5310   else
5311     {
5312       /* this is the default return value: we cannot know if a class
5313        * is going to paint outside its allocation, so we take the
5314        * conservative approach.
5315        */
5316       res = FALSE;
5317     }
5318
5319   /* update_default_paint_volume() should only fail if one of the children
5320    * reported an invalid, or no, paint volume
5321    */
5322   if (!clutter_actor_update_default_paint_volume (self, volume))
5323     return FALSE;
5324
5325   return res;
5326 }
5327
5328 /**
5329  * clutter_actor_get_default_paint_volume:
5330  * @self: a #ClutterActor
5331  *
5332  * Retrieves the default paint volume for @self.
5333  *
5334  * This function provides the same #ClutterPaintVolume that would be
5335  * computed by the default implementation inside #ClutterActor of the
5336  * #ClutterActorClass.get_paint_volume() virtual function.
5337  *
5338  * This function should only be used by #ClutterActor subclasses that
5339  * cannot chain up to the parent implementation when computing their
5340  * paint volume.
5341  *
5342  * Return value: (transfer none): a pointer to the default
5343  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5344  *   the actor could not compute a valid paint volume. The returned value
5345  *   is not guaranteed to be stable across multiple frames, so if you
5346  *   want to retain it, you will need to copy it using
5347  *   clutter_paint_volume_copy().
5348  *
5349  * Since: 1.10
5350  */
5351 const ClutterPaintVolume *
5352 clutter_actor_get_default_paint_volume (ClutterActor *self)
5353 {
5354   ClutterPaintVolume volume;
5355   ClutterPaintVolume *res;
5356
5357   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5358
5359   res = NULL;
5360   _clutter_paint_volume_init_static (&volume, self);
5361   if (clutter_actor_update_default_paint_volume (self, &volume))
5362     {
5363       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5364
5365       if (stage != NULL)
5366         {
5367           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5368           _clutter_paint_volume_copy_static (&volume, res);
5369         }
5370     }
5371
5372   clutter_paint_volume_free (&volume);
5373
5374   return res;
5375 }
5376
5377 static gboolean
5378 clutter_actor_real_has_overlaps (ClutterActor *self)
5379 {
5380   /* By default we'll assume that all actors need an offscreen redirect to get
5381    * the correct opacity. Actors such as ClutterTexture that would never need
5382    * an offscreen redirect can override this to return FALSE. */
5383   return TRUE;
5384 }
5385
5386 static void
5387 clutter_actor_real_destroy (ClutterActor *actor)
5388 {
5389   ClutterActorIter iter;
5390
5391   g_object_freeze_notify (G_OBJECT (actor));
5392
5393   clutter_actor_iter_init (&iter, actor);
5394   while (clutter_actor_iter_next (&iter, NULL))
5395     clutter_actor_iter_destroy (&iter);
5396
5397   g_object_thaw_notify (G_OBJECT (actor));
5398 }
5399
5400 static GObject *
5401 clutter_actor_constructor (GType gtype,
5402                            guint n_props,
5403                            GObjectConstructParam *props)
5404 {
5405   GObjectClass *gobject_class;
5406   ClutterActor *self;
5407   GObject *retval;
5408
5409   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5410   retval = gobject_class->constructor (gtype, n_props, props);
5411   self = CLUTTER_ACTOR (retval);
5412
5413   if (self->priv->layout_manager == NULL)
5414     {
5415       ClutterLayoutManager *default_layout;
5416
5417       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5418
5419       default_layout = clutter_fixed_layout_new ();
5420       clutter_actor_set_layout_manager (self, default_layout);
5421     }
5422
5423   return retval;
5424 }
5425
5426 static void
5427 clutter_actor_class_init (ClutterActorClass *klass)
5428 {
5429   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5430
5431   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5432   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5433   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5434   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5435
5436   object_class->constructor = clutter_actor_constructor;
5437   object_class->set_property = clutter_actor_set_property;
5438   object_class->get_property = clutter_actor_get_property;
5439   object_class->dispose = clutter_actor_dispose;
5440   object_class->finalize = clutter_actor_finalize;
5441
5442   klass->show = clutter_actor_real_show;
5443   klass->show_all = clutter_actor_show;
5444   klass->hide = clutter_actor_real_hide;
5445   klass->hide_all = clutter_actor_hide;
5446   klass->map = clutter_actor_real_map;
5447   klass->unmap = clutter_actor_real_unmap;
5448   klass->unrealize = clutter_actor_real_unrealize;
5449   klass->pick = clutter_actor_real_pick;
5450   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5451   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5452   klass->allocate = clutter_actor_real_allocate;
5453   klass->queue_redraw = clutter_actor_real_queue_redraw;
5454   klass->queue_relayout = clutter_actor_real_queue_relayout;
5455   klass->apply_transform = clutter_actor_real_apply_transform;
5456   klass->get_accessible = clutter_actor_real_get_accessible;
5457   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5458   klass->has_overlaps = clutter_actor_real_has_overlaps;
5459   klass->paint = clutter_actor_real_paint;
5460   klass->destroy = clutter_actor_real_destroy;
5461
5462   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5463
5464   /**
5465    * ClutterActor:x:
5466    *
5467    * X coordinate of the actor in pixels. If written, forces a fixed
5468    * position for the actor. If read, returns the fixed position if any,
5469    * otherwise the allocation if available, otherwise 0.
5470    *
5471    * The #ClutterActor:x property is animatable.
5472    */
5473   obj_props[PROP_X] =
5474     g_param_spec_float ("x",
5475                         P_("X coordinate"),
5476                         P_("X coordinate of the actor"),
5477                         -G_MAXFLOAT, G_MAXFLOAT,
5478                         0.0,
5479                         G_PARAM_READWRITE |
5480                         G_PARAM_STATIC_STRINGS |
5481                         CLUTTER_PARAM_ANIMATABLE);
5482
5483   /**
5484    * ClutterActor:y:
5485    *
5486    * Y coordinate of the actor in pixels. If written, forces a fixed
5487    * position for the actor.  If read, returns the fixed position if
5488    * any, otherwise the allocation if available, otherwise 0.
5489    *
5490    * The #ClutterActor:y property is animatable.
5491    */
5492   obj_props[PROP_Y] =
5493     g_param_spec_float ("y",
5494                         P_("Y coordinate"),
5495                         P_("Y coordinate of the actor"),
5496                         -G_MAXFLOAT, G_MAXFLOAT,
5497                         0.0,
5498                         G_PARAM_READWRITE |
5499                         G_PARAM_STATIC_STRINGS |
5500                         CLUTTER_PARAM_ANIMATABLE);
5501
5502   /**
5503    * ClutterActor:position:
5504    *
5505    * The position of the origin of the actor.
5506    *
5507    * This property is a shorthand for setting and getting the
5508    * #ClutterActor:x and #ClutterActor:y properties at the same
5509    * time.
5510    *
5511    * The #ClutterActor:position property is animatable.
5512    *
5513    * Since: 1.12
5514    */
5515   obj_props[PROP_POSITION] =
5516     g_param_spec_boxed ("position",
5517                         P_("Position"),
5518                         P_("The position of the origin of the actor"),
5519                         CLUTTER_TYPE_POINT,
5520                         G_PARAM_READWRITE |
5521                         G_PARAM_STATIC_STRINGS |
5522                         CLUTTER_PARAM_ANIMATABLE);
5523
5524   /**
5525    * ClutterActor:width:
5526    *
5527    * Width of the actor (in pixels). If written, forces the minimum and
5528    * natural size request of the actor to the given width. If read, returns
5529    * the allocated width if available, otherwise the width request.
5530    *
5531    * The #ClutterActor:width property is animatable.
5532    */
5533   obj_props[PROP_WIDTH] =
5534     g_param_spec_float ("width",
5535                         P_("Width"),
5536                         P_("Width of the actor"),
5537                         0.0, G_MAXFLOAT,
5538                         0.0,
5539                         G_PARAM_READWRITE |
5540                         G_PARAM_STATIC_STRINGS |
5541                         CLUTTER_PARAM_ANIMATABLE);
5542
5543   /**
5544    * ClutterActor:height:
5545    *
5546    * Height of the actor (in pixels).  If written, forces the minimum and
5547    * natural size request of the actor to the given height. If read, returns
5548    * the allocated height if available, otherwise the height request.
5549    *
5550    * The #ClutterActor:height property is animatable.
5551    */
5552   obj_props[PROP_HEIGHT] =
5553     g_param_spec_float ("height",
5554                         P_("Height"),
5555                         P_("Height of the actor"),
5556                         0.0, G_MAXFLOAT,
5557                         0.0,
5558                         G_PARAM_READWRITE |
5559                         G_PARAM_STATIC_STRINGS |
5560                         CLUTTER_PARAM_ANIMATABLE);
5561
5562   /**
5563    * ClutterActor:size:
5564    *
5565    * The size of the actor.
5566    *
5567    * This property is a shorthand for setting and getting the
5568    * #ClutterActor:width and #ClutterActor:height at the same time.
5569    *
5570    * The #ClutterActor:size property is animatable.
5571    *
5572    * Since: 1.12
5573    */
5574   obj_props[PROP_SIZE] =
5575     g_param_spec_boxed ("size",
5576                         P_("Size"),
5577                         P_("The size of the actor"),
5578                         CLUTTER_TYPE_SIZE,
5579                         G_PARAM_READWRITE |
5580                         G_PARAM_STATIC_STRINGS |
5581                         CLUTTER_PARAM_ANIMATABLE);
5582
5583   /**
5584    * ClutterActor:fixed-x:
5585    *
5586    * The fixed X position of the actor in pixels.
5587    *
5588    * Writing this property sets #ClutterActor:fixed-position-set
5589    * property as well, as a side effect
5590    *
5591    * Since: 0.8
5592    */
5593   obj_props[PROP_FIXED_X] =
5594     g_param_spec_float ("fixed-x",
5595                         P_("Fixed X"),
5596                         P_("Forced X position of the actor"),
5597                         -G_MAXFLOAT, G_MAXFLOAT,
5598                         0.0,
5599                         CLUTTER_PARAM_READWRITE);
5600
5601   /**
5602    * ClutterActor:fixed-y:
5603    *
5604    * The fixed Y position of the actor in pixels.
5605    *
5606    * Writing this property sets the #ClutterActor:fixed-position-set
5607    * property as well, as a side effect
5608    *
5609    * Since: 0.8
5610    */
5611   obj_props[PROP_FIXED_Y] =
5612     g_param_spec_float ("fixed-y",
5613                         P_("Fixed Y"),
5614                         P_("Forced Y position of the actor"),
5615                         -G_MAXFLOAT, G_MAXFLOAT,
5616                         0,
5617                         CLUTTER_PARAM_READWRITE);
5618
5619   /**
5620    * ClutterActor:fixed-position-set:
5621    *
5622    * This flag controls whether the #ClutterActor:fixed-x and
5623    * #ClutterActor:fixed-y properties are used
5624    *
5625    * Since: 0.8
5626    */
5627   obj_props[PROP_FIXED_POSITION_SET] =
5628     g_param_spec_boolean ("fixed-position-set",
5629                           P_("Fixed position set"),
5630                           P_("Whether to use fixed positioning for the actor"),
5631                           FALSE,
5632                           CLUTTER_PARAM_READWRITE);
5633
5634   /**
5635    * ClutterActor:min-width:
5636    *
5637    * A forced minimum width request for the actor, in pixels
5638    *
5639    * Writing this property sets the #ClutterActor:min-width-set property
5640    * as well, as a side effect.
5641    *
5642    *This property overrides the usual width request of the actor.
5643    *
5644    * Since: 0.8
5645    */
5646   obj_props[PROP_MIN_WIDTH] =
5647     g_param_spec_float ("min-width",
5648                         P_("Min Width"),
5649                         P_("Forced minimum width request for the actor"),
5650                         0.0, G_MAXFLOAT,
5651                         0.0,
5652                         CLUTTER_PARAM_READWRITE);
5653
5654   /**
5655    * ClutterActor:min-height:
5656    *
5657    * A forced minimum height request for the actor, in pixels
5658    *
5659    * Writing this property sets the #ClutterActor:min-height-set property
5660    * as well, as a side effect. This property overrides the usual height
5661    * request of the actor.
5662    *
5663    * Since: 0.8
5664    */
5665   obj_props[PROP_MIN_HEIGHT] =
5666     g_param_spec_float ("min-height",
5667                         P_("Min Height"),
5668                         P_("Forced minimum height request for the actor"),
5669                         0.0, G_MAXFLOAT,
5670                         0.0,
5671                         CLUTTER_PARAM_READWRITE);
5672
5673   /**
5674    * ClutterActor:natural-width:
5675    *
5676    * A forced natural width request for the actor, in pixels
5677    *
5678    * Writing this property sets the #ClutterActor:natural-width-set
5679    * property as well, as a side effect. This property overrides the
5680    * usual width request of the actor
5681    *
5682    * Since: 0.8
5683    */
5684   obj_props[PROP_NATURAL_WIDTH] =
5685     g_param_spec_float ("natural-width",
5686                         P_("Natural Width"),
5687                         P_("Forced natural width request for the actor"),
5688                         0.0, G_MAXFLOAT,
5689                         0.0,
5690                         CLUTTER_PARAM_READWRITE);
5691
5692   /**
5693    * ClutterActor:natural-height:
5694    *
5695    * A forced natural height request for the actor, in pixels
5696    *
5697    * Writing this property sets the #ClutterActor:natural-height-set
5698    * property as well, as a side effect. This property overrides the
5699    * usual height request of the actor
5700    *
5701    * Since: 0.8
5702    */
5703   obj_props[PROP_NATURAL_HEIGHT] =
5704     g_param_spec_float ("natural-height",
5705                         P_("Natural Height"),
5706                         P_("Forced natural height request for the actor"),
5707                         0.0, G_MAXFLOAT,
5708                         0.0,
5709                         CLUTTER_PARAM_READWRITE);
5710
5711   /**
5712    * ClutterActor:min-width-set:
5713    *
5714    * This flag controls whether the #ClutterActor:min-width property
5715    * is used
5716    *
5717    * Since: 0.8
5718    */
5719   obj_props[PROP_MIN_WIDTH_SET] =
5720     g_param_spec_boolean ("min-width-set",
5721                           P_("Minimum width set"),
5722                           P_("Whether to use the min-width property"),
5723                           FALSE,
5724                           CLUTTER_PARAM_READWRITE);
5725
5726   /**
5727    * ClutterActor:min-height-set:
5728    *
5729    * This flag controls whether the #ClutterActor:min-height property
5730    * is used
5731    *
5732    * Since: 0.8
5733    */
5734   obj_props[PROP_MIN_HEIGHT_SET] =
5735     g_param_spec_boolean ("min-height-set",
5736                           P_("Minimum height set"),
5737                           P_("Whether to use the min-height property"),
5738                           FALSE,
5739                           CLUTTER_PARAM_READWRITE);
5740
5741   /**
5742    * ClutterActor:natural-width-set:
5743    *
5744    * This flag controls whether the #ClutterActor:natural-width property
5745    * is used
5746    *
5747    * Since: 0.8
5748    */
5749   obj_props[PROP_NATURAL_WIDTH_SET] =
5750     g_param_spec_boolean ("natural-width-set",
5751                           P_("Natural width set"),
5752                           P_("Whether to use the natural-width property"),
5753                           FALSE,
5754                           CLUTTER_PARAM_READWRITE);
5755
5756   /**
5757    * ClutterActor:natural-height-set:
5758    *
5759    * This flag controls whether the #ClutterActor:natural-height property
5760    * is used
5761    *
5762    * Since: 0.8
5763    */
5764   obj_props[PROP_NATURAL_HEIGHT_SET] =
5765     g_param_spec_boolean ("natural-height-set",
5766                           P_("Natural height set"),
5767                           P_("Whether to use the natural-height property"),
5768                           FALSE,
5769                           CLUTTER_PARAM_READWRITE);
5770
5771   /**
5772    * ClutterActor:allocation:
5773    *
5774    * The allocation for the actor, in pixels
5775    *
5776    * This is property is read-only, but you might monitor it to know when an
5777    * actor moves or resizes
5778    *
5779    * Since: 0.8
5780    */
5781   obj_props[PROP_ALLOCATION] =
5782     g_param_spec_boxed ("allocation",
5783                         P_("Allocation"),
5784                         P_("The actor's allocation"),
5785                         CLUTTER_TYPE_ACTOR_BOX,
5786                         CLUTTER_PARAM_READABLE);
5787
5788   /**
5789    * ClutterActor:request-mode:
5790    *
5791    * Request mode for the #ClutterActor. The request mode determines the
5792    * type of geometry management used by the actor, either height for width
5793    * (the default) or width for height.
5794    *
5795    * For actors implementing height for width, the parent container should get
5796    * the preferred width first, and then the preferred height for that width.
5797    *
5798    * For actors implementing width for height, the parent container should get
5799    * the preferred height first, and then the preferred width for that height.
5800    *
5801    * For instance:
5802    *
5803    * |[
5804    *   ClutterRequestMode mode;
5805    *   gfloat natural_width, min_width;
5806    *   gfloat natural_height, min_height;
5807    *
5808    *   mode = clutter_actor_get_request_mode (child);
5809    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5810    *     {
5811    *       clutter_actor_get_preferred_width (child, -1,
5812    *                                          &amp;min_width,
5813    *                                          &amp;natural_width);
5814    *       clutter_actor_get_preferred_height (child, natural_width,
5815    *                                           &amp;min_height,
5816    *                                           &amp;natural_height);
5817    *     }
5818    *   else
5819    *     {
5820    *       clutter_actor_get_preferred_height (child, -1,
5821    *                                           &amp;min_height,
5822    *                                           &amp;natural_height);
5823    *       clutter_actor_get_preferred_width (child, natural_height,
5824    *                                          &amp;min_width,
5825    *                                          &amp;natural_width);
5826    *     }
5827    * ]|
5828    *
5829    * will retrieve the minimum and natural width and height depending on the
5830    * preferred request mode of the #ClutterActor "child".
5831    *
5832    * The clutter_actor_get_preferred_size() function will implement this
5833    * check for you.
5834    *
5835    * Since: 0.8
5836    */
5837   obj_props[PROP_REQUEST_MODE] =
5838     g_param_spec_enum ("request-mode",
5839                        P_("Request Mode"),
5840                        P_("The actor's request mode"),
5841                        CLUTTER_TYPE_REQUEST_MODE,
5842                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5843                        CLUTTER_PARAM_READWRITE);
5844
5845   /**
5846    * ClutterActor:depth:
5847    *
5848    * The position of the actor on the Z axis.
5849    *
5850    * The #ClutterActor:depth property is relative to the parent's
5851    * modelview matrix.
5852    *
5853    * The #ClutterActor:depth property is animatable.
5854    *
5855    * Since: 0.6
5856    */
5857   obj_props[PROP_DEPTH] =
5858     g_param_spec_float ("depth",
5859                         P_("Depth"),
5860                         P_("Position on the Z axis"),
5861                         -G_MAXFLOAT, G_MAXFLOAT,
5862                         0.0,
5863                         G_PARAM_READWRITE |
5864                         G_PARAM_STATIC_STRINGS |
5865                         CLUTTER_PARAM_ANIMATABLE);
5866
5867   /**
5868    * ClutterActor:opacity:
5869    *
5870    * Opacity of an actor, between 0 (fully transparent) and
5871    * 255 (fully opaque)
5872    *
5873    * The #ClutterActor:opacity property is animatable.
5874    */
5875   obj_props[PROP_OPACITY] =
5876     g_param_spec_uint ("opacity",
5877                        P_("Opacity"),
5878                        P_("Opacity of an actor"),
5879                        0, 255,
5880                        255,
5881                        G_PARAM_READWRITE |
5882                        G_PARAM_STATIC_STRINGS |
5883                        CLUTTER_PARAM_ANIMATABLE);
5884
5885   /**
5886    * ClutterActor:offscreen-redirect:
5887    *
5888    * Determines the conditions in which the actor will be redirected
5889    * to an offscreen framebuffer while being painted. For example this
5890    * can be used to cache an actor in a framebuffer or for improved
5891    * handling of transparent actors. See
5892    * clutter_actor_set_offscreen_redirect() for details.
5893    *
5894    * Since: 1.8
5895    */
5896   obj_props[PROP_OFFSCREEN_REDIRECT] =
5897     g_param_spec_flags ("offscreen-redirect",
5898                         P_("Offscreen redirect"),
5899                         P_("Flags controlling when to flatten the actor into a single image"),
5900                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5901                         0,
5902                         CLUTTER_PARAM_READWRITE);
5903
5904   /**
5905    * ClutterActor:visible:
5906    *
5907    * Whether the actor is set to be visible or not
5908    *
5909    * See also #ClutterActor:mapped
5910    */
5911   obj_props[PROP_VISIBLE] =
5912     g_param_spec_boolean ("visible",
5913                           P_("Visible"),
5914                           P_("Whether the actor is visible or not"),
5915                           FALSE,
5916                           CLUTTER_PARAM_READWRITE);
5917
5918   /**
5919    * ClutterActor:mapped:
5920    *
5921    * Whether the actor is mapped (will be painted when the stage
5922    * to which it belongs is mapped)
5923    *
5924    * Since: 1.0
5925    */
5926   obj_props[PROP_MAPPED] =
5927     g_param_spec_boolean ("mapped",
5928                           P_("Mapped"),
5929                           P_("Whether the actor will be painted"),
5930                           FALSE,
5931                           CLUTTER_PARAM_READABLE);
5932
5933   /**
5934    * ClutterActor:realized:
5935    *
5936    * Whether the actor has been realized
5937    *
5938    * Since: 1.0
5939    */
5940   obj_props[PROP_REALIZED] =
5941     g_param_spec_boolean ("realized",
5942                           P_("Realized"),
5943                           P_("Whether the actor has been realized"),
5944                           FALSE,
5945                           CLUTTER_PARAM_READABLE);
5946
5947   /**
5948    * ClutterActor:reactive:
5949    *
5950    * Whether the actor is reactive to events or not
5951    *
5952    * Only reactive actors will emit event-related signals
5953    *
5954    * Since: 0.6
5955    */
5956   obj_props[PROP_REACTIVE] =
5957     g_param_spec_boolean ("reactive",
5958                           P_("Reactive"),
5959                           P_("Whether the actor is reactive to events"),
5960                           FALSE,
5961                           CLUTTER_PARAM_READWRITE);
5962
5963   /**
5964    * ClutterActor:has-clip:
5965    *
5966    * Whether the actor has the #ClutterActor:clip property set or not
5967    */
5968   obj_props[PROP_HAS_CLIP] =
5969     g_param_spec_boolean ("has-clip",
5970                           P_("Has Clip"),
5971                           P_("Whether the actor has a clip set"),
5972                           FALSE,
5973                           CLUTTER_PARAM_READABLE);
5974
5975   /**
5976    * ClutterActor:clip:
5977    *
5978    * The clip region for the actor, in actor-relative coordinates
5979    *
5980    * Every part of the actor outside the clip region will not be
5981    * painted
5982    */
5983   obj_props[PROP_CLIP] =
5984     g_param_spec_boxed ("clip",
5985                         P_("Clip"),
5986                         P_("The clip region for the actor"),
5987                         CLUTTER_TYPE_GEOMETRY,
5988                         CLUTTER_PARAM_READWRITE);
5989
5990   /**
5991    * ClutterActor:name:
5992    *
5993    * The name of the actor
5994    *
5995    * Since: 0.2
5996    */
5997   obj_props[PROP_NAME] =
5998     g_param_spec_string ("name",
5999                          P_("Name"),
6000                          P_("Name of the actor"),
6001                          NULL,
6002                          CLUTTER_PARAM_READWRITE);
6003
6004   /**
6005    * ClutterActor:scale-x:
6006    *
6007    * The horizontal scale of the actor.
6008    *
6009    * The #ClutterActor:scale-x property is animatable.
6010    *
6011    * Since: 0.6
6012    */
6013   obj_props[PROP_SCALE_X] =
6014     g_param_spec_double ("scale-x",
6015                          P_("Scale X"),
6016                          P_("Scale factor on the X axis"),
6017                          0.0, G_MAXDOUBLE,
6018                          1.0,
6019                          G_PARAM_READWRITE |
6020                          G_PARAM_STATIC_STRINGS |
6021                          CLUTTER_PARAM_ANIMATABLE);
6022
6023   /**
6024    * ClutterActor:scale-y:
6025    *
6026    * The vertical scale of the actor.
6027    *
6028    * The #ClutterActor:scale-y property is animatable.
6029    *
6030    * Since: 0.6
6031    */
6032   obj_props[PROP_SCALE_Y] =
6033     g_param_spec_double ("scale-y",
6034                          P_("Scale Y"),
6035                          P_("Scale factor on the Y axis"),
6036                          0.0, G_MAXDOUBLE,
6037                          1.0,
6038                          G_PARAM_READWRITE |
6039                          G_PARAM_STATIC_STRINGS |
6040                          CLUTTER_PARAM_ANIMATABLE);
6041
6042   /**
6043    * ClutterActor:scale-center-x:
6044    *
6045    * The horizontal center point for scaling
6046    *
6047    * Since: 1.0
6048    */
6049   obj_props[PROP_SCALE_CENTER_X] =
6050     g_param_spec_float ("scale-center-x",
6051                         P_("Scale Center X"),
6052                         P_("Horizontal scale center"),
6053                         -G_MAXFLOAT, G_MAXFLOAT,
6054                         0.0,
6055                         CLUTTER_PARAM_READWRITE);
6056
6057   /**
6058    * ClutterActor:scale-center-y:
6059    *
6060    * The vertical center point for scaling
6061    *
6062    * Since: 1.0
6063    */
6064   obj_props[PROP_SCALE_CENTER_Y] =
6065     g_param_spec_float ("scale-center-y",
6066                         P_("Scale Center Y"),
6067                         P_("Vertical scale center"),
6068                         -G_MAXFLOAT, G_MAXFLOAT,
6069                         0.0,
6070                         CLUTTER_PARAM_READWRITE);
6071
6072   /**
6073    * ClutterActor:scale-gravity:
6074    *
6075    * The center point for scaling expressed as a #ClutterGravity
6076    *
6077    * Since: 1.0
6078    */
6079   obj_props[PROP_SCALE_GRAVITY] =
6080     g_param_spec_enum ("scale-gravity",
6081                        P_("Scale Gravity"),
6082                        P_("The center of scaling"),
6083                        CLUTTER_TYPE_GRAVITY,
6084                        CLUTTER_GRAVITY_NONE,
6085                        CLUTTER_PARAM_READWRITE);
6086
6087   /**
6088    * ClutterActor:rotation-angle-x:
6089    *
6090    * The rotation angle on the X axis.
6091    *
6092    * The #ClutterActor:rotation-angle-x property is animatable.
6093    *
6094    * Since: 0.6
6095    */
6096   obj_props[PROP_ROTATION_ANGLE_X] =
6097     g_param_spec_double ("rotation-angle-x",
6098                          P_("Rotation Angle X"),
6099                          P_("The rotation angle on the X axis"),
6100                          -G_MAXDOUBLE, G_MAXDOUBLE,
6101                          0.0,
6102                          G_PARAM_READWRITE |
6103                          G_PARAM_STATIC_STRINGS |
6104                          CLUTTER_PARAM_ANIMATABLE);
6105
6106   /**
6107    * ClutterActor:rotation-angle-y:
6108    *
6109    * The rotation angle on the Y axis
6110    *
6111    * The #ClutterActor:rotation-angle-y property is animatable.
6112    *
6113    * Since: 0.6
6114    */
6115   obj_props[PROP_ROTATION_ANGLE_Y] =
6116     g_param_spec_double ("rotation-angle-y",
6117                          P_("Rotation Angle Y"),
6118                          P_("The rotation angle on the Y axis"),
6119                          -G_MAXDOUBLE, G_MAXDOUBLE,
6120                          0.0,
6121                          G_PARAM_READWRITE |
6122                          G_PARAM_STATIC_STRINGS |
6123                          CLUTTER_PARAM_ANIMATABLE);
6124
6125   /**
6126    * ClutterActor:rotation-angle-z:
6127    *
6128    * The rotation angle on the Z axis
6129    *
6130    * The #ClutterActor:rotation-angle-z property is animatable.
6131    *
6132    * Since: 0.6
6133    */
6134   obj_props[PROP_ROTATION_ANGLE_Z] =
6135     g_param_spec_double ("rotation-angle-z",
6136                          P_("Rotation Angle Z"),
6137                          P_("The rotation angle on the Z axis"),
6138                          -G_MAXDOUBLE, G_MAXDOUBLE,
6139                          0.0,
6140                          G_PARAM_READWRITE |
6141                          G_PARAM_STATIC_STRINGS |
6142                          CLUTTER_PARAM_ANIMATABLE);
6143
6144   /**
6145    * ClutterActor:rotation-center-x:
6146    *
6147    * The rotation center on the X axis.
6148    *
6149    * Since: 0.6
6150    */
6151   obj_props[PROP_ROTATION_CENTER_X] =
6152     g_param_spec_boxed ("rotation-center-x",
6153                         P_("Rotation Center X"),
6154                         P_("The rotation center on the X axis"),
6155                         CLUTTER_TYPE_VERTEX,
6156                         CLUTTER_PARAM_READWRITE);
6157
6158   /**
6159    * ClutterActor:rotation-center-y:
6160    *
6161    * The rotation center on the Y axis.
6162    *
6163    * Since: 0.6
6164    */
6165   obj_props[PROP_ROTATION_CENTER_Y] =
6166     g_param_spec_boxed ("rotation-center-y",
6167                         P_("Rotation Center Y"),
6168                         P_("The rotation center on the Y axis"),
6169                         CLUTTER_TYPE_VERTEX,
6170                         CLUTTER_PARAM_READWRITE);
6171
6172   /**
6173    * ClutterActor:rotation-center-z:
6174    *
6175    * The rotation center on the Z axis.
6176    *
6177    * Since: 0.6
6178    */
6179   obj_props[PROP_ROTATION_CENTER_Z] =
6180     g_param_spec_boxed ("rotation-center-z",
6181                         P_("Rotation Center Z"),
6182                         P_("The rotation center on the Z axis"),
6183                         CLUTTER_TYPE_VERTEX,
6184                         CLUTTER_PARAM_READWRITE);
6185
6186   /**
6187    * ClutterActor:rotation-center-z-gravity:
6188    *
6189    * The rotation center on the Z axis expressed as a #ClutterGravity.
6190    *
6191    * Since: 1.0
6192    */
6193   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6194     g_param_spec_enum ("rotation-center-z-gravity",
6195                        P_("Rotation Center Z Gravity"),
6196                        P_("Center point for rotation around the Z axis"),
6197                        CLUTTER_TYPE_GRAVITY,
6198                        CLUTTER_GRAVITY_NONE,
6199                        CLUTTER_PARAM_READWRITE);
6200
6201   /**
6202    * ClutterActor:anchor-x:
6203    *
6204    * The X coordinate of an actor's anchor point, relative to
6205    * the actor coordinate space, in pixels
6206    *
6207    * Since: 0.8
6208    */
6209   obj_props[PROP_ANCHOR_X] =
6210     g_param_spec_float ("anchor-x",
6211                         P_("Anchor X"),
6212                         P_("X coordinate of the anchor point"),
6213                         -G_MAXFLOAT, G_MAXFLOAT,
6214                         0,
6215                         CLUTTER_PARAM_READWRITE);
6216
6217   /**
6218    * ClutterActor:anchor-y:
6219    *
6220    * The Y coordinate of an actor's anchor point, relative to
6221    * the actor coordinate space, in pixels
6222    *
6223    * Since: 0.8
6224    */
6225   obj_props[PROP_ANCHOR_Y] =
6226     g_param_spec_float ("anchor-y",
6227                         P_("Anchor Y"),
6228                         P_("Y coordinate of the anchor point"),
6229                         -G_MAXFLOAT, G_MAXFLOAT,
6230                         0,
6231                         CLUTTER_PARAM_READWRITE);
6232
6233   /**
6234    * ClutterActor:anchor-gravity:
6235    *
6236    * The anchor point expressed as a #ClutterGravity
6237    *
6238    * Since: 1.0
6239    */
6240   obj_props[PROP_ANCHOR_GRAVITY] =
6241     g_param_spec_enum ("anchor-gravity",
6242                        P_("Anchor Gravity"),
6243                        P_("The anchor point as a ClutterGravity"),
6244                        CLUTTER_TYPE_GRAVITY,
6245                        CLUTTER_GRAVITY_NONE,
6246                        CLUTTER_PARAM_READWRITE);
6247
6248   /**
6249    * ClutterActor:show-on-set-parent:
6250    *
6251    * If %TRUE, the actor is automatically shown when parented.
6252    *
6253    * Calling clutter_actor_hide() on an actor which has not been
6254    * parented will set this property to %FALSE as a side effect.
6255    *
6256    * Since: 0.8
6257    */
6258   obj_props[PROP_SHOW_ON_SET_PARENT] =
6259     g_param_spec_boolean ("show-on-set-parent",
6260                           P_("Show on set parent"),
6261                           P_("Whether the actor is shown when parented"),
6262                           TRUE,
6263                           CLUTTER_PARAM_READWRITE);
6264
6265   /**
6266    * ClutterActor:clip-to-allocation:
6267    *
6268    * Whether the clip region should track the allocated area
6269    * of the actor.
6270    *
6271    * This property is ignored if a clip area has been explicitly
6272    * set using clutter_actor_set_clip().
6273    *
6274    * Since: 1.0
6275    */
6276   obj_props[PROP_CLIP_TO_ALLOCATION] =
6277     g_param_spec_boolean ("clip-to-allocation",
6278                           P_("Clip to Allocation"),
6279                           P_("Sets the clip region to track the actor's allocation"),
6280                           FALSE,
6281                           CLUTTER_PARAM_READWRITE);
6282
6283   /**
6284    * ClutterActor:text-direction:
6285    *
6286    * The direction of the text inside a #ClutterActor.
6287    *
6288    * Since: 1.0
6289    */
6290   obj_props[PROP_TEXT_DIRECTION] =
6291     g_param_spec_enum ("text-direction",
6292                        P_("Text Direction"),
6293                        P_("Direction of the text"),
6294                        CLUTTER_TYPE_TEXT_DIRECTION,
6295                        CLUTTER_TEXT_DIRECTION_LTR,
6296                        CLUTTER_PARAM_READWRITE);
6297
6298   /**
6299    * ClutterActor:has-pointer:
6300    *
6301    * Whether the actor contains the pointer of a #ClutterInputDevice
6302    * or not.
6303    *
6304    * Since: 1.2
6305    */
6306   obj_props[PROP_HAS_POINTER] =
6307     g_param_spec_boolean ("has-pointer",
6308                           P_("Has Pointer"),
6309                           P_("Whether the actor contains the pointer of an input device"),
6310                           FALSE,
6311                           CLUTTER_PARAM_READABLE);
6312
6313   /**
6314    * ClutterActor:actions:
6315    *
6316    * Adds a #ClutterAction to the actor
6317    *
6318    * Since: 1.4
6319    */
6320   obj_props[PROP_ACTIONS] =
6321     g_param_spec_object ("actions",
6322                          P_("Actions"),
6323                          P_("Adds an action to the actor"),
6324                          CLUTTER_TYPE_ACTION,
6325                          CLUTTER_PARAM_WRITABLE);
6326
6327   /**
6328    * ClutterActor:constraints:
6329    *
6330    * Adds a #ClutterConstraint to the actor
6331    *
6332    * Since: 1.4
6333    */
6334   obj_props[PROP_CONSTRAINTS] =
6335     g_param_spec_object ("constraints",
6336                          P_("Constraints"),
6337                          P_("Adds a constraint to the actor"),
6338                          CLUTTER_TYPE_CONSTRAINT,
6339                          CLUTTER_PARAM_WRITABLE);
6340
6341   /**
6342    * ClutterActor:effect:
6343    *
6344    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6345    *
6346    * Since: 1.4
6347    */
6348   obj_props[PROP_EFFECT] =
6349     g_param_spec_object ("effect",
6350                          P_("Effect"),
6351                          P_("Add an effect to be applied on the actor"),
6352                          CLUTTER_TYPE_EFFECT,
6353                          CLUTTER_PARAM_WRITABLE);
6354
6355   /**
6356    * ClutterActor:layout-manager:
6357    *
6358    * A delegate object for controlling the layout of the children of
6359    * an actor.
6360    *
6361    * Since: 1.10
6362    */
6363   obj_props[PROP_LAYOUT_MANAGER] =
6364     g_param_spec_object ("layout-manager",
6365                          P_("Layout Manager"),
6366                          P_("The object controlling the layout of an actor's children"),
6367                          CLUTTER_TYPE_LAYOUT_MANAGER,
6368                          CLUTTER_PARAM_READWRITE);
6369
6370
6371   /**
6372    * ClutterActor:x-align:
6373    *
6374    * The alignment of an actor on the X axis, if the actor has been given
6375    * extra space for its allocation.
6376    *
6377    * Since: 1.10
6378    */
6379   obj_props[PROP_X_ALIGN] =
6380     g_param_spec_enum ("x-align",
6381                        P_("X Alignment"),
6382                        P_("The alignment of the actor on the X axis within its allocation"),
6383                        CLUTTER_TYPE_ACTOR_ALIGN,
6384                        CLUTTER_ACTOR_ALIGN_FILL,
6385                        CLUTTER_PARAM_READWRITE);
6386
6387   /**
6388    * ClutterActor:y-align:
6389    *
6390    * The alignment of an actor on the Y axis, if the actor has been given
6391    * extra space for its allocation.
6392    *
6393    * Since: 1.10
6394    */
6395   obj_props[PROP_Y_ALIGN] =
6396     g_param_spec_enum ("y-align",
6397                        P_("Y Alignment"),
6398                        P_("The alignment of the actor on the Y axis within its allocation"),
6399                        CLUTTER_TYPE_ACTOR_ALIGN,
6400                        CLUTTER_ACTOR_ALIGN_FILL,
6401                        CLUTTER_PARAM_READWRITE);
6402
6403   /**
6404    * ClutterActor:margin-top:
6405    *
6406    * The margin (in pixels) from the top of the actor.
6407    *
6408    * This property adds a margin to the actor's preferred size; the margin
6409    * will be automatically taken into account when allocating the actor.
6410    *
6411    * Since: 1.10
6412    */
6413   obj_props[PROP_MARGIN_TOP] =
6414     g_param_spec_float ("margin-top",
6415                         P_("Margin Top"),
6416                         P_("Extra space at the top"),
6417                         0.0, G_MAXFLOAT,
6418                         0.0,
6419                         CLUTTER_PARAM_READWRITE);
6420
6421   /**
6422    * ClutterActor:margin-bottom:
6423    *
6424    * The margin (in pixels) from the bottom of the actor.
6425    *
6426    * This property adds a margin to the actor's preferred size; the margin
6427    * will be automatically taken into account when allocating the actor.
6428    *
6429    * Since: 1.10
6430    */
6431   obj_props[PROP_MARGIN_BOTTOM] =
6432     g_param_spec_float ("margin-bottom",
6433                         P_("Margin Bottom"),
6434                         P_("Extra space at the bottom"),
6435                         0.0, G_MAXFLOAT,
6436                         0.0,
6437                         CLUTTER_PARAM_READWRITE);
6438
6439   /**
6440    * ClutterActor:margin-left:
6441    *
6442    * The margin (in pixels) from the left of the actor.
6443    *
6444    * This property adds a margin to the actor's preferred size; the margin
6445    * will be automatically taken into account when allocating the actor.
6446    *
6447    * Since: 1.10
6448    */
6449   obj_props[PROP_MARGIN_LEFT] =
6450     g_param_spec_float ("margin-left",
6451                         P_("Margin Left"),
6452                         P_("Extra space at the left"),
6453                         0.0, G_MAXFLOAT,
6454                         0.0,
6455                         CLUTTER_PARAM_READWRITE);
6456
6457   /**
6458    * ClutterActor:margin-right:
6459    *
6460    * The margin (in pixels) from the right of the actor.
6461    *
6462    * This property adds a margin to the actor's preferred size; the margin
6463    * will be automatically taken into account when allocating the actor.
6464    *
6465    * Since: 1.10
6466    */
6467   obj_props[PROP_MARGIN_RIGHT] =
6468     g_param_spec_float ("margin-right",
6469                         P_("Margin Right"),
6470                         P_("Extra space at the right"),
6471                         0.0, G_MAXFLOAT,
6472                         0.0,
6473                         CLUTTER_PARAM_READWRITE);
6474
6475   /**
6476    * ClutterActor:background-color-set:
6477    *
6478    * Whether the #ClutterActor:background-color property has been set.
6479    *
6480    * Since: 1.10
6481    */
6482   obj_props[PROP_BACKGROUND_COLOR_SET] =
6483     g_param_spec_boolean ("background-color-set",
6484                           P_("Background Color Set"),
6485                           P_("Whether the background color is set"),
6486                           FALSE,
6487                           CLUTTER_PARAM_READABLE);
6488
6489   /**
6490    * ClutterActor:background-color:
6491    *
6492    * Paints a solid fill of the actor's allocation using the specified
6493    * color.
6494    *
6495    * The #ClutterActor:background-color property is animatable.
6496    *
6497    * Since: 1.10
6498    */
6499   obj_props[PROP_BACKGROUND_COLOR] =
6500     clutter_param_spec_color ("background-color",
6501                               P_("Background color"),
6502                               P_("The actor's background color"),
6503                               CLUTTER_COLOR_Transparent,
6504                               G_PARAM_READWRITE |
6505                               G_PARAM_STATIC_STRINGS |
6506                               CLUTTER_PARAM_ANIMATABLE);
6507
6508   /**
6509    * ClutterActor:first-child:
6510    *
6511    * The actor's first child.
6512    *
6513    * Since: 1.10
6514    */
6515   obj_props[PROP_FIRST_CHILD] =
6516     g_param_spec_object ("first-child",
6517                          P_("First Child"),
6518                          P_("The actor's first child"),
6519                          CLUTTER_TYPE_ACTOR,
6520                          CLUTTER_PARAM_READABLE);
6521
6522   /**
6523    * ClutterActor:last-child:
6524    *
6525    * The actor's last child.
6526    *
6527    * Since: 1.10
6528    */
6529   obj_props[PROP_LAST_CHILD] =
6530     g_param_spec_object ("last-child",
6531                          P_("Last Child"),
6532                          P_("The actor's last child"),
6533                          CLUTTER_TYPE_ACTOR,
6534                          CLUTTER_PARAM_READABLE);
6535
6536   /**
6537    * ClutterActor:content:
6538    *
6539    * The #ClutterContent implementation that controls the content
6540    * of the actor.
6541    *
6542    * Since: 1.10
6543    */
6544   obj_props[PROP_CONTENT] =
6545     g_param_spec_object ("content",
6546                          P_("Content"),
6547                          P_("Delegate object for painting the actor's content"),
6548                          CLUTTER_TYPE_CONTENT,
6549                          CLUTTER_PARAM_READWRITE);
6550
6551   /**
6552    * ClutterActor:content-gravity:
6553    *
6554    * The alignment that should be honoured by the #ClutterContent
6555    * set with the #ClutterActor:content property.
6556    *
6557    * Changing the value of this property will change the bounding box of
6558    * the content; you can use the #ClutterActor:content-box property to
6559    * get the position and size of the content within the actor's
6560    * allocation.
6561    *
6562    * This property is meaningful only for #ClutterContent implementations
6563    * that have a preferred size, and if the preferred size is smaller than
6564    * the actor's allocation.
6565    *
6566    * The #ClutterActor:content-gravity property is animatable.
6567    *
6568    * Since: 1.10
6569    */
6570   obj_props[PROP_CONTENT_GRAVITY] =
6571     g_param_spec_enum ("content-gravity",
6572                        P_("Content Gravity"),
6573                        P_("Alignment of the actor's content"),
6574                        CLUTTER_TYPE_CONTENT_GRAVITY,
6575                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6576                        CLUTTER_PARAM_READWRITE);
6577
6578   /**
6579    * ClutterActor:content-box:
6580    *
6581    * The bounding box for the #ClutterContent used by the actor.
6582    *
6583    * The value of this property is controlled by the #ClutterActor:allocation
6584    * and #ClutterActor:content-gravity properties of #ClutterActor.
6585    *
6586    * The bounding box for the content is guaranteed to never exceed the
6587    * allocation's of the actor.
6588    *
6589    * Since: 1.10
6590    */
6591   obj_props[PROP_CONTENT_BOX] =
6592     g_param_spec_boxed ("content-box",
6593                         P_("Content Box"),
6594                         P_("The bounding box of the actor's content"),
6595                         CLUTTER_TYPE_ACTOR_BOX,
6596                         G_PARAM_READABLE |
6597                         G_PARAM_STATIC_STRINGS |
6598                         CLUTTER_PARAM_ANIMATABLE);
6599
6600   obj_props[PROP_MINIFICATION_FILTER] =
6601     g_param_spec_enum ("minification-filter",
6602                        P_("Minification Filter"),
6603                        P_("The filter used when reducing the size of the content"),
6604                        CLUTTER_TYPE_SCALING_FILTER,
6605                        CLUTTER_SCALING_FILTER_LINEAR,
6606                        CLUTTER_PARAM_READWRITE);
6607
6608   obj_props[PROP_MAGNIFICATION_FILTER] =
6609     g_param_spec_enum ("magnification-filter",
6610                        P_("Magnification Filter"),
6611                        P_("The filter used when increasing the size of the content"),
6612                        CLUTTER_TYPE_SCALING_FILTER,
6613                        CLUTTER_SCALING_FILTER_LINEAR,
6614                        CLUTTER_PARAM_READWRITE);
6615
6616   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6617
6618   /**
6619    * ClutterActor::destroy:
6620    * @actor: the #ClutterActor which emitted the signal
6621    *
6622    * The ::destroy signal notifies that all references held on the
6623    * actor which emitted it should be released.
6624    *
6625    * The ::destroy signal should be used by all holders of a reference
6626    * on @actor.
6627    *
6628    * This signal might result in the finalization of the #ClutterActor
6629    * if all references are released.
6630    *
6631    * Composite actors and actors implementing the #ClutterContainer
6632    * interface should override the default implementation of the
6633    * class handler of this signal and call clutter_actor_destroy() on
6634    * their children. When overriding the default class handler, it is
6635    * required to chain up to the parent's implementation.
6636    *
6637    * Since: 0.2
6638    */
6639   actor_signals[DESTROY] =
6640     g_signal_new (I_("destroy"),
6641                   G_TYPE_FROM_CLASS (object_class),
6642                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6643                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6644                   NULL, NULL,
6645                   _clutter_marshal_VOID__VOID,
6646                   G_TYPE_NONE, 0);
6647   /**
6648    * ClutterActor::show:
6649    * @actor: the object which received the signal
6650    *
6651    * The ::show signal is emitted when an actor is visible and
6652    * rendered on the stage.
6653    *
6654    * Since: 0.2
6655    */
6656   actor_signals[SHOW] =
6657     g_signal_new (I_("show"),
6658                   G_TYPE_FROM_CLASS (object_class),
6659                   G_SIGNAL_RUN_FIRST,
6660                   G_STRUCT_OFFSET (ClutterActorClass, show),
6661                   NULL, NULL,
6662                   _clutter_marshal_VOID__VOID,
6663                   G_TYPE_NONE, 0);
6664   /**
6665    * ClutterActor::hide:
6666    * @actor: the object which received the signal
6667    *
6668    * The ::hide signal is emitted when an actor is no longer rendered
6669    * on the stage.
6670    *
6671    * Since: 0.2
6672    */
6673   actor_signals[HIDE] =
6674     g_signal_new (I_("hide"),
6675                   G_TYPE_FROM_CLASS (object_class),
6676                   G_SIGNAL_RUN_FIRST,
6677                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6678                   NULL, NULL,
6679                   _clutter_marshal_VOID__VOID,
6680                   G_TYPE_NONE, 0);
6681   /**
6682    * ClutterActor::parent-set:
6683    * @actor: the object which received the signal
6684    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6685    *
6686    * This signal is emitted when the parent of the actor changes.
6687    *
6688    * Since: 0.2
6689    */
6690   actor_signals[PARENT_SET] =
6691     g_signal_new (I_("parent-set"),
6692                   G_TYPE_FROM_CLASS (object_class),
6693                   G_SIGNAL_RUN_LAST,
6694                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6695                   NULL, NULL,
6696                   _clutter_marshal_VOID__OBJECT,
6697                   G_TYPE_NONE, 1,
6698                   CLUTTER_TYPE_ACTOR);
6699
6700   /**
6701    * ClutterActor::queue-redraw:
6702    * @actor: the actor we're bubbling the redraw request through
6703    * @origin: the actor which initiated the redraw request
6704    *
6705    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6706    * is called on @origin.
6707    *
6708    * The default implementation for #ClutterActor chains up to the
6709    * parent actor and queues a redraw on the parent, thus "bubbling"
6710    * the redraw queue up through the actor graph. The default
6711    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6712    * in a main loop idle handler.
6713    *
6714    * Note that the @origin actor may be the stage, or a container; it
6715    * does not have to be a leaf node in the actor graph.
6716    *
6717    * Toolkits embedding a #ClutterStage which require a redraw and
6718    * relayout cycle can stop the emission of this signal using the
6719    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6720    * themselves, like:
6721    *
6722    * |[
6723    *   static void
6724    *   on_redraw_complete (gpointer data)
6725    *   {
6726    *     ClutterStage *stage = data;
6727    *
6728    *     /&ast; execute the Clutter drawing pipeline &ast;/
6729    *     clutter_stage_ensure_redraw (stage);
6730    *   }
6731    *
6732    *   static void
6733    *   on_stage_queue_redraw (ClutterStage *stage)
6734    *   {
6735    *     /&ast; this prevents the default handler to run &ast;/
6736    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6737    *
6738    *     /&ast; queue a redraw with the host toolkit and call
6739    *      &ast; a function when the redraw has been completed
6740    *      &ast;/
6741    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6742    *   }
6743    * ]|
6744    *
6745    * <note><para>This signal is emitted before the Clutter paint
6746    * pipeline is executed. If you want to know when the pipeline has
6747    * been completed you should connect to the ::paint signal on the
6748    * Stage with g_signal_connect_after().</para></note>
6749    *
6750    * Since: 1.0
6751    */
6752   actor_signals[QUEUE_REDRAW] =
6753     g_signal_new (I_("queue-redraw"),
6754                   G_TYPE_FROM_CLASS (object_class),
6755                   G_SIGNAL_RUN_LAST |
6756                   G_SIGNAL_NO_HOOKS,
6757                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6758                   NULL, NULL,
6759                   _clutter_marshal_VOID__OBJECT,
6760                   G_TYPE_NONE, 1,
6761                   CLUTTER_TYPE_ACTOR);
6762
6763   /**
6764    * ClutterActor::queue-relayout
6765    * @actor: the actor being queued for relayout
6766    *
6767    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6768    * is called on an actor.
6769    *
6770    * The default implementation for #ClutterActor chains up to the
6771    * parent actor and queues a relayout on the parent, thus "bubbling"
6772    * the relayout queue up through the actor graph.
6773    *
6774    * The main purpose of this signal is to allow relayout to be propagated
6775    * properly in the procense of #ClutterClone actors. Applications will
6776    * not normally need to connect to this signal.
6777    *
6778    * Since: 1.2
6779    */
6780   actor_signals[QUEUE_RELAYOUT] =
6781     g_signal_new (I_("queue-relayout"),
6782                   G_TYPE_FROM_CLASS (object_class),
6783                   G_SIGNAL_RUN_LAST |
6784                   G_SIGNAL_NO_HOOKS,
6785                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6786                   NULL, NULL,
6787                   _clutter_marshal_VOID__VOID,
6788                   G_TYPE_NONE, 0);
6789
6790   /**
6791    * ClutterActor::event:
6792    * @actor: the actor which received the event
6793    * @event: a #ClutterEvent
6794    *
6795    * The ::event signal is emitted each time an event is received
6796    * by the @actor. This signal will be emitted on every actor,
6797    * following the hierarchy chain, until it reaches the top-level
6798    * container (the #ClutterStage).
6799    *
6800    * Return value: %TRUE if the event has been handled by the actor,
6801    *   or %FALSE to continue the emission.
6802    *
6803    * Since: 0.6
6804    */
6805   actor_signals[EVENT] =
6806     g_signal_new (I_("event"),
6807                   G_TYPE_FROM_CLASS (object_class),
6808                   G_SIGNAL_RUN_LAST,
6809                   G_STRUCT_OFFSET (ClutterActorClass, event),
6810                   _clutter_boolean_handled_accumulator, NULL,
6811                   _clutter_marshal_BOOLEAN__BOXED,
6812                   G_TYPE_BOOLEAN, 1,
6813                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6814   /**
6815    * ClutterActor::button-press-event:
6816    * @actor: the actor which received the event
6817    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6818    *
6819    * The ::button-press-event signal is emitted each time a mouse button
6820    * is pressed on @actor.
6821    *
6822    * Return value: %TRUE if the event has been handled by the actor,
6823    *   or %FALSE to continue the emission.
6824    *
6825    * Since: 0.6
6826    */
6827   actor_signals[BUTTON_PRESS_EVENT] =
6828     g_signal_new (I_("button-press-event"),
6829                   G_TYPE_FROM_CLASS (object_class),
6830                   G_SIGNAL_RUN_LAST,
6831                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6832                   _clutter_boolean_handled_accumulator, NULL,
6833                   _clutter_marshal_BOOLEAN__BOXED,
6834                   G_TYPE_BOOLEAN, 1,
6835                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6836   /**
6837    * ClutterActor::button-release-event:
6838    * @actor: the actor which received the event
6839    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6840    *
6841    * The ::button-release-event signal is emitted each time a mouse button
6842    * is released on @actor.
6843    *
6844    * Return value: %TRUE if the event has been handled by the actor,
6845    *   or %FALSE to continue the emission.
6846    *
6847    * Since: 0.6
6848    */
6849   actor_signals[BUTTON_RELEASE_EVENT] =
6850     g_signal_new (I_("button-release-event"),
6851                   G_TYPE_FROM_CLASS (object_class),
6852                   G_SIGNAL_RUN_LAST,
6853                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6854                   _clutter_boolean_handled_accumulator, NULL,
6855                   _clutter_marshal_BOOLEAN__BOXED,
6856                   G_TYPE_BOOLEAN, 1,
6857                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6858   /**
6859    * ClutterActor::scroll-event:
6860    * @actor: the actor which received the event
6861    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6862    *
6863    * The ::scroll-event signal is emitted each time the mouse is
6864    * scrolled on @actor
6865    *
6866    * Return value: %TRUE if the event has been handled by the actor,
6867    *   or %FALSE to continue the emission.
6868    *
6869    * Since: 0.6
6870    */
6871   actor_signals[SCROLL_EVENT] =
6872     g_signal_new (I_("scroll-event"),
6873                   G_TYPE_FROM_CLASS (object_class),
6874                   G_SIGNAL_RUN_LAST,
6875                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6876                   _clutter_boolean_handled_accumulator, NULL,
6877                   _clutter_marshal_BOOLEAN__BOXED,
6878                   G_TYPE_BOOLEAN, 1,
6879                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6880   /**
6881    * ClutterActor::key-press-event:
6882    * @actor: the actor which received the event
6883    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6884    *
6885    * The ::key-press-event signal is emitted each time a keyboard button
6886    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6887    *
6888    * Return value: %TRUE if the event has been handled by the actor,
6889    *   or %FALSE to continue the emission.
6890    *
6891    * Since: 0.6
6892    */
6893   actor_signals[KEY_PRESS_EVENT] =
6894     g_signal_new (I_("key-press-event"),
6895                   G_TYPE_FROM_CLASS (object_class),
6896                   G_SIGNAL_RUN_LAST,
6897                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6898                   _clutter_boolean_handled_accumulator, NULL,
6899                   _clutter_marshal_BOOLEAN__BOXED,
6900                   G_TYPE_BOOLEAN, 1,
6901                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6902   /**
6903    * ClutterActor::key-release-event:
6904    * @actor: the actor which received the event
6905    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6906    *
6907    * The ::key-release-event signal is emitted each time a keyboard button
6908    * is released while @actor has key focus (see
6909    * clutter_stage_set_key_focus()).
6910    *
6911    * Return value: %TRUE if the event has been handled by the actor,
6912    *   or %FALSE to continue the emission.
6913    *
6914    * Since: 0.6
6915    */
6916   actor_signals[KEY_RELEASE_EVENT] =
6917     g_signal_new (I_("key-release-event"),
6918                   G_TYPE_FROM_CLASS (object_class),
6919                   G_SIGNAL_RUN_LAST,
6920                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6921                   _clutter_boolean_handled_accumulator, NULL,
6922                   _clutter_marshal_BOOLEAN__BOXED,
6923                   G_TYPE_BOOLEAN, 1,
6924                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6925   /**
6926    * ClutterActor::motion-event:
6927    * @actor: the actor which received the event
6928    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6929    *
6930    * The ::motion-event signal is emitted each time the mouse pointer is
6931    * moved over @actor.
6932    *
6933    * Return value: %TRUE if the event has been handled by the actor,
6934    *   or %FALSE to continue the emission.
6935    *
6936    * Since: 0.6
6937    */
6938   actor_signals[MOTION_EVENT] =
6939     g_signal_new (I_("motion-event"),
6940                   G_TYPE_FROM_CLASS (object_class),
6941                   G_SIGNAL_RUN_LAST,
6942                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6943                   _clutter_boolean_handled_accumulator, NULL,
6944                   _clutter_marshal_BOOLEAN__BOXED,
6945                   G_TYPE_BOOLEAN, 1,
6946                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6947
6948   /**
6949    * ClutterActor::key-focus-in:
6950    * @actor: the actor which now has key focus
6951    *
6952    * The ::key-focus-in signal is emitted when @actor receives key focus.
6953    *
6954    * Since: 0.6
6955    */
6956   actor_signals[KEY_FOCUS_IN] =
6957     g_signal_new (I_("key-focus-in"),
6958                   G_TYPE_FROM_CLASS (object_class),
6959                   G_SIGNAL_RUN_LAST,
6960                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6961                   NULL, NULL,
6962                   _clutter_marshal_VOID__VOID,
6963                   G_TYPE_NONE, 0);
6964
6965   /**
6966    * ClutterActor::key-focus-out:
6967    * @actor: the actor which now has key focus
6968    *
6969    * The ::key-focus-out signal is emitted when @actor loses key focus.
6970    *
6971    * Since: 0.6
6972    */
6973   actor_signals[KEY_FOCUS_OUT] =
6974     g_signal_new (I_("key-focus-out"),
6975                   G_TYPE_FROM_CLASS (object_class),
6976                   G_SIGNAL_RUN_LAST,
6977                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6978                   NULL, NULL,
6979                   _clutter_marshal_VOID__VOID,
6980                   G_TYPE_NONE, 0);
6981
6982   /**
6983    * ClutterActor::enter-event:
6984    * @actor: the actor which the pointer has entered.
6985    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6986    *
6987    * The ::enter-event signal is emitted when the pointer enters the @actor
6988    *
6989    * Return value: %TRUE if the event has been handled by the actor,
6990    *   or %FALSE to continue the emission.
6991    *
6992    * Since: 0.6
6993    */
6994   actor_signals[ENTER_EVENT] =
6995     g_signal_new (I_("enter-event"),
6996                   G_TYPE_FROM_CLASS (object_class),
6997                   G_SIGNAL_RUN_LAST,
6998                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6999                   _clutter_boolean_handled_accumulator, NULL,
7000                   _clutter_marshal_BOOLEAN__BOXED,
7001                   G_TYPE_BOOLEAN, 1,
7002                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7003
7004   /**
7005    * ClutterActor::leave-event:
7006    * @actor: the actor which the pointer has left
7007    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7008    *
7009    * The ::leave-event signal is emitted when the pointer leaves the @actor.
7010    *
7011    * Return value: %TRUE if the event has been handled by the actor,
7012    *   or %FALSE to continue the emission.
7013    *
7014    * Since: 0.6
7015    */
7016   actor_signals[LEAVE_EVENT] =
7017     g_signal_new (I_("leave-event"),
7018                   G_TYPE_FROM_CLASS (object_class),
7019                   G_SIGNAL_RUN_LAST,
7020                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7021                   _clutter_boolean_handled_accumulator, NULL,
7022                   _clutter_marshal_BOOLEAN__BOXED,
7023                   G_TYPE_BOOLEAN, 1,
7024                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7025
7026   /**
7027    * ClutterActor::captured-event:
7028    * @actor: the actor which received the signal
7029    * @event: a #ClutterEvent
7030    *
7031    * The ::captured-event signal is emitted when an event is captured
7032    * by Clutter. This signal will be emitted starting from the top-level
7033    * container (the #ClutterStage) to the actor which received the event
7034    * going down the hierarchy. This signal can be used to intercept every
7035    * event before the specialized events (like
7036    * ClutterActor::button-press-event or ::key-released-event) are
7037    * emitted.
7038    *
7039    * Return value: %TRUE if the event has been handled by the actor,
7040    *   or %FALSE to continue the emission.
7041    *
7042    * Since: 0.6
7043    */
7044   actor_signals[CAPTURED_EVENT] =
7045     g_signal_new (I_("captured-event"),
7046                   G_TYPE_FROM_CLASS (object_class),
7047                   G_SIGNAL_RUN_LAST,
7048                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7049                   _clutter_boolean_handled_accumulator, NULL,
7050                   _clutter_marshal_BOOLEAN__BOXED,
7051                   G_TYPE_BOOLEAN, 1,
7052                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7053
7054   /**
7055    * ClutterActor::paint:
7056    * @actor: the #ClutterActor that received the signal
7057    *
7058    * The ::paint signal is emitted each time an actor is being painted.
7059    *
7060    * Subclasses of #ClutterActor should override the class signal handler
7061    * and paint themselves in that function.
7062    *
7063    * It is possible to connect a handler to the ::paint signal in order
7064    * to set up some custom aspect of a paint.
7065    *
7066    * Since: 0.8
7067    */
7068   actor_signals[PAINT] =
7069     g_signal_new (I_("paint"),
7070                   G_TYPE_FROM_CLASS (object_class),
7071                   G_SIGNAL_RUN_LAST |
7072                   G_SIGNAL_NO_HOOKS,
7073                   G_STRUCT_OFFSET (ClutterActorClass, paint),
7074                   NULL, NULL,
7075                   _clutter_marshal_VOID__VOID,
7076                   G_TYPE_NONE, 0);
7077   /**
7078    * ClutterActor::realize:
7079    * @actor: the #ClutterActor that received the signal
7080    *
7081    * The ::realize signal is emitted each time an actor is being
7082    * realized.
7083    *
7084    * Since: 0.8
7085    */
7086   actor_signals[REALIZE] =
7087     g_signal_new (I_("realize"),
7088                   G_TYPE_FROM_CLASS (object_class),
7089                   G_SIGNAL_RUN_LAST,
7090                   G_STRUCT_OFFSET (ClutterActorClass, realize),
7091                   NULL, NULL,
7092                   _clutter_marshal_VOID__VOID,
7093                   G_TYPE_NONE, 0);
7094   /**
7095    * ClutterActor::unrealize:
7096    * @actor: the #ClutterActor that received the signal
7097    *
7098    * The ::unrealize signal is emitted each time an actor is being
7099    * unrealized.
7100    *
7101    * Since: 0.8
7102    */
7103   actor_signals[UNREALIZE] =
7104     g_signal_new (I_("unrealize"),
7105                   G_TYPE_FROM_CLASS (object_class),
7106                   G_SIGNAL_RUN_LAST,
7107                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7108                   NULL, NULL,
7109                   _clutter_marshal_VOID__VOID,
7110                   G_TYPE_NONE, 0);
7111
7112   /**
7113    * ClutterActor::pick:
7114    * @actor: the #ClutterActor that received the signal
7115    * @color: the #ClutterColor to be used when picking
7116    *
7117    * The ::pick signal is emitted each time an actor is being painted
7118    * in "pick mode". The pick mode is used to identify the actor during
7119    * the event handling phase, or by clutter_stage_get_actor_at_pos().
7120    * The actor should paint its shape using the passed @pick_color.
7121    *
7122    * Subclasses of #ClutterActor should override the class signal handler
7123    * and paint themselves in that function.
7124    *
7125    * It is possible to connect a handler to the ::pick signal in order
7126    * to set up some custom aspect of a paint in pick mode.
7127    *
7128    * Since: 1.0
7129    */
7130   actor_signals[PICK] =
7131     g_signal_new (I_("pick"),
7132                   G_TYPE_FROM_CLASS (object_class),
7133                   G_SIGNAL_RUN_LAST,
7134                   G_STRUCT_OFFSET (ClutterActorClass, pick),
7135                   NULL, NULL,
7136                   _clutter_marshal_VOID__BOXED,
7137                   G_TYPE_NONE, 1,
7138                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7139
7140   /**
7141    * ClutterActor::allocation-changed:
7142    * @actor: the #ClutterActor that emitted the signal
7143    * @box: a #ClutterActorBox with the new allocation
7144    * @flags: #ClutterAllocationFlags for the allocation
7145    *
7146    * The ::allocation-changed signal is emitted when the
7147    * #ClutterActor:allocation property changes. Usually, application
7148    * code should just use the notifications for the :allocation property
7149    * but if you want to track the allocation flags as well, for instance
7150    * to know whether the absolute origin of @actor changed, then you might
7151    * want use this signal instead.
7152    *
7153    * Since: 1.0
7154    */
7155   actor_signals[ALLOCATION_CHANGED] =
7156     g_signal_new (I_("allocation-changed"),
7157                   G_TYPE_FROM_CLASS (object_class),
7158                   G_SIGNAL_RUN_LAST,
7159                   0,
7160                   NULL, NULL,
7161                   _clutter_marshal_VOID__BOXED_FLAGS,
7162                   G_TYPE_NONE, 2,
7163                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7164                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7165
7166   /**
7167    * ClutterActor::transitions-completed:
7168    * @actor: a #ClutterActor
7169    *
7170    * The ::transitions-completed signal is emitted once all transitions
7171    * involving @actor are complete.
7172    *
7173    * Since: 1.10
7174    */
7175   actor_signals[TRANSITIONS_COMPLETED] =
7176     g_signal_new (I_("transitions-completed"),
7177                   G_TYPE_FROM_CLASS (object_class),
7178                   G_SIGNAL_RUN_LAST,
7179                   0,
7180                   NULL, NULL,
7181                   _clutter_marshal_VOID__VOID,
7182                   G_TYPE_NONE, 0);
7183 }
7184
7185 static void
7186 clutter_actor_init (ClutterActor *self)
7187 {
7188   ClutterActorPrivate *priv;
7189
7190   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7191
7192   priv->id = _clutter_context_acquire_id (self);
7193   priv->pick_id = -1;
7194
7195   priv->opacity = 0xff;
7196   priv->show_on_set_parent = TRUE;
7197
7198   priv->needs_width_request = TRUE;
7199   priv->needs_height_request = TRUE;
7200   priv->needs_allocation = TRUE;
7201
7202   priv->cached_width_age = 1;
7203   priv->cached_height_age = 1;
7204
7205   priv->opacity_override = -1;
7206   priv->enable_model_view_transform = TRUE;
7207
7208   /* Initialize an empty paint volume to start with */
7209   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7210   priv->last_paint_volume_valid = TRUE;
7211
7212   priv->transform_valid = FALSE;
7213
7214   /* the default is to stretch the content, to match the
7215    * current behaviour of basically all actors. also, it's
7216    * the easiest thing to compute.
7217    */
7218   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7219   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7220   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7221 }
7222
7223 /**
7224  * clutter_actor_new:
7225  *
7226  * Creates a new #ClutterActor.
7227  *
7228  * A newly created actor has a floating reference, which will be sunk
7229  * when it is added to another actor.
7230  *
7231  * Return value: (transfer full): the newly created #ClutterActor
7232  *
7233  * Since: 1.10
7234  */
7235 ClutterActor *
7236 clutter_actor_new (void)
7237 {
7238   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7239 }
7240
7241 /**
7242  * clutter_actor_destroy:
7243  * @self: a #ClutterActor
7244  *
7245  * Destroys an actor.  When an actor is destroyed, it will break any
7246  * references it holds to other objects.  If the actor is inside a
7247  * container, the actor will be removed.
7248  *
7249  * When you destroy a container, its children will be destroyed as well.
7250  *
7251  * Note: you cannot destroy the #ClutterStage returned by
7252  * clutter_stage_get_default().
7253  */
7254 void
7255 clutter_actor_destroy (ClutterActor *self)
7256 {
7257   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7258
7259   g_object_ref (self);
7260
7261   /* avoid recursion while destroying */
7262   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7263     {
7264       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7265
7266       g_object_run_dispose (G_OBJECT (self));
7267
7268       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7269     }
7270
7271   g_object_unref (self);
7272 }
7273
7274 void
7275 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7276                                     ClutterPaintVolume *clip)
7277 {
7278   ClutterActorPrivate *priv = self->priv;
7279   ClutterPaintVolume *pv;
7280   gboolean clipped;
7281
7282   /* Remove queue entry early in the process, otherwise a new
7283      queue_redraw() during signal handling could put back this
7284      object in the stage redraw list (but the entry is freed as
7285      soon as we return from this function, causing a segfault
7286      later)
7287   */
7288   priv->queue_redraw_entry = NULL;
7289
7290   /* If we've been explicitly passed a clip volume then there's
7291    * nothing more to calculate, but otherwise the only thing we know
7292    * is that the change is constrained to the given actor.
7293    *
7294    * The idea is that if we know the paint volume for where the actor
7295    * was last drawn (in eye coordinates) and we also have the paint
7296    * volume for where it will be drawn next (in actor coordinates)
7297    * then if we queue a redraw for both these volumes that will cover
7298    * everything that needs to be redrawn to clear the old view and
7299    * show the latest view of the actor.
7300    *
7301    * Don't clip this redraw if we don't know what position we had for
7302    * the previous redraw since we don't know where to set the clip so
7303    * it will clear the actor as it is currently.
7304    */
7305   if (clip)
7306     {
7307       _clutter_actor_set_queue_redraw_clip (self, clip);
7308       clipped = TRUE;
7309     }
7310   else if (G_LIKELY (priv->last_paint_volume_valid))
7311     {
7312       pv = _clutter_actor_get_paint_volume_mutable (self);
7313       if (pv)
7314         {
7315           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7316
7317           /* make sure we redraw the actors old position... */
7318           _clutter_actor_set_queue_redraw_clip (stage,
7319                                                 &priv->last_paint_volume);
7320           _clutter_actor_signal_queue_redraw (stage, stage);
7321           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7322
7323           /* XXX: Ideally the redraw signal would take a clip volume
7324            * argument, but that would be an ABI break. Until we can
7325            * break the ABI we pass the argument out-of-band
7326            */
7327
7328           /* setup the clip for the actors new position... */
7329           _clutter_actor_set_queue_redraw_clip (self, pv);
7330           clipped = TRUE;
7331         }
7332       else
7333         clipped = FALSE;
7334     }
7335   else
7336     clipped = FALSE;
7337
7338   _clutter_actor_signal_queue_redraw (self, self);
7339
7340   /* Just in case anyone is manually firing redraw signals without
7341    * using the public queue_redraw() API we are careful to ensure that
7342    * our out-of-band clip member is cleared before returning...
7343    *
7344    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7345    */
7346   if (G_LIKELY (clipped))
7347     _clutter_actor_set_queue_redraw_clip (self, NULL);
7348 }
7349
7350 static void
7351 _clutter_actor_get_allocation_clip (ClutterActor *self,
7352                                     ClutterActorBox *clip)
7353 {
7354   ClutterActorBox allocation;
7355
7356   /* XXX: we don't care if we get an out of date allocation here
7357    * because clutter_actor_queue_redraw_with_clip knows to ignore
7358    * the clip if the actor's allocation is invalid.
7359    *
7360    * This is noted because clutter_actor_get_allocation_box does some
7361    * unnecessary work to support buggy code with a comment suggesting
7362    * that it could be changed later which would be good for this use
7363    * case!
7364    */
7365   clutter_actor_get_allocation_box (self, &allocation);
7366
7367   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7368    * actor's own coordinate space but the allocation is in parent
7369    * coordinates */
7370   clip->x1 = 0;
7371   clip->y1 = 0;
7372   clip->x2 = allocation.x2 - allocation.x1;
7373   clip->y2 = allocation.y2 - allocation.y1;
7374 }
7375
7376 void
7377 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7378                                   ClutterRedrawFlags  flags,
7379                                   ClutterPaintVolume *volume,
7380                                   ClutterEffect      *effect)
7381 {
7382   ClutterActorPrivate *priv = self->priv;
7383   ClutterPaintVolume allocation_pv;
7384   ClutterPaintVolume *pv;
7385   gboolean should_free_pv;
7386   ClutterActor *stage;
7387
7388   /* Here's an outline of the actor queue redraw mechanism:
7389    *
7390    * The process starts in one of the following two functions which
7391    * are wrappers for this function:
7392    * clutter_actor_queue_redraw
7393    * _clutter_actor_queue_redraw_with_clip
7394    *
7395    * additionally, an effect can queue a redraw by wrapping this
7396    * function in clutter_effect_queue_rerun
7397    *
7398    * This functions queues an entry in a list associated with the
7399    * stage which is a list of actors that queued a redraw while
7400    * updating the timelines, performing layouting and processing other
7401    * mainloop sources before the next paint starts.
7402    *
7403    * We aim to minimize the processing done at this point because
7404    * there is a good chance other events will happen while updating
7405    * the scenegraph that would invalidate any expensive work we might
7406    * otherwise try to do here. For example we don't try and resolve
7407    * the screen space bounding box of an actor at this stage so as to
7408    * minimize how much of the screen redraw because it's possible
7409    * something else will happen which will force a full redraw anyway.
7410    *
7411    * When all updates are complete and we come to paint the stage then
7412    * we iterate this list and actually emit the "queue-redraw" signals
7413    * for each of the listed actors which will bubble up to the stage
7414    * for each actor and at that point we will transform the actors
7415    * paint volume into screen coordinates to determine the clip region
7416    * for what needs to be redrawn in the next paint.
7417    *
7418    * Besides minimizing redundant work another reason for this
7419    * deferred design is that it's more likely we will be able to
7420    * determine the paint volume of an actor once we've finished
7421    * updating the scenegraph because its allocation should be up to
7422    * date. NB: If we can't determine an actors paint volume then we
7423    * can't automatically queue a clipped redraw which can make a big
7424    * difference to performance.
7425    *
7426    * So the control flow goes like this:
7427    * One of clutter_actor_queue_redraw,
7428    *        _clutter_actor_queue_redraw_with_clip
7429    *     or clutter_effect_queue_rerun
7430    *
7431    * then control moves to:
7432    *   _clutter_stage_queue_actor_redraw
7433    *
7434    * later during _clutter_stage_do_update, once relayouting is done
7435    * and the scenegraph has been updated we will call:
7436    * _clutter_stage_finish_queue_redraws
7437    *
7438    * _clutter_stage_finish_queue_redraws will call
7439    * _clutter_actor_finish_queue_redraw for each listed actor.
7440    * Note: actors *are* allowed to queue further redraws during this
7441    * process (considering clone actors or texture_new_from_actor which
7442    * respond to their source queueing a redraw by queuing a redraw
7443    * themselves). We repeat the process until the list is empty.
7444    *
7445    * This will result in the "queue-redraw" signal being fired for
7446    * each actor which will pass control to the default signal handler:
7447    * clutter_actor_real_queue_redraw
7448    *
7449    * This will bubble up to the stages handler:
7450    * clutter_stage_real_queue_redraw
7451    *
7452    * clutter_stage_real_queue_redraw will transform the actors paint
7453    * volume into screen space and add it as a clip region for the next
7454    * paint.
7455    */
7456
7457   /* ignore queueing a redraw for actors being destroyed */
7458   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7459     return;
7460
7461   stage = _clutter_actor_get_stage_internal (self);
7462
7463   /* Ignore queueing a redraw for actors not descended from a stage */
7464   if (stage == NULL)
7465     return;
7466
7467   /* ignore queueing a redraw on stages that are being destroyed */
7468   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7469     return;
7470
7471   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7472     {
7473       ClutterActorBox allocation_clip;
7474       ClutterVertex origin;
7475
7476       /* If the actor doesn't have a valid allocation then we will
7477        * queue a full stage redraw. */
7478       if (priv->needs_allocation)
7479         {
7480           /* NB: NULL denotes an undefined clip which will result in a
7481            * full redraw... */
7482           _clutter_actor_set_queue_redraw_clip (self, NULL);
7483           _clutter_actor_signal_queue_redraw (self, self);
7484           return;
7485         }
7486
7487       _clutter_paint_volume_init_static (&allocation_pv, self);
7488       pv = &allocation_pv;
7489
7490       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7491
7492       origin.x = allocation_clip.x1;
7493       origin.y = allocation_clip.y1;
7494       origin.z = 0;
7495       clutter_paint_volume_set_origin (pv, &origin);
7496       clutter_paint_volume_set_width (pv,
7497                                       allocation_clip.x2 - allocation_clip.x1);
7498       clutter_paint_volume_set_height (pv,
7499                                        allocation_clip.y2 -
7500                                        allocation_clip.y1);
7501       should_free_pv = TRUE;
7502     }
7503   else
7504     {
7505       pv = volume;
7506       should_free_pv = FALSE;
7507     }
7508
7509   self->priv->queue_redraw_entry =
7510     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7511                                        priv->queue_redraw_entry,
7512                                        self,
7513                                        pv);
7514
7515   if (should_free_pv)
7516     clutter_paint_volume_free (pv);
7517
7518   /* If this is the first redraw queued then we can directly use the
7519      effect parameter */
7520   if (!priv->is_dirty)
7521     priv->effect_to_redraw = effect;
7522   /* Otherwise we need to merge it with the existing effect parameter */
7523   else if (effect != NULL)
7524     {
7525       /* If there's already an effect then we need to use whichever is
7526          later in the chain of actors. Otherwise a full redraw has
7527          already been queued on the actor so we need to ignore the
7528          effect parameter */
7529       if (priv->effect_to_redraw != NULL)
7530         {
7531           if (priv->effects == NULL)
7532             g_warning ("Redraw queued with an effect that is "
7533                        "not applied to the actor");
7534           else
7535             {
7536               const GList *l;
7537
7538               for (l = _clutter_meta_group_peek_metas (priv->effects);
7539                    l != NULL;
7540                    l = l->next)
7541                 {
7542                   if (l->data == priv->effect_to_redraw ||
7543                       l->data == effect)
7544                     priv->effect_to_redraw = l->data;
7545                 }
7546             }
7547         }
7548     }
7549   else
7550     {
7551       /* If no effect is specified then we need to redraw the whole
7552          actor */
7553       priv->effect_to_redraw = NULL;
7554     }
7555
7556   priv->is_dirty = TRUE;
7557 }
7558
7559 /**
7560  * clutter_actor_queue_redraw:
7561  * @self: A #ClutterActor
7562  *
7563  * Queues up a redraw of an actor and any children. The redraw occurs
7564  * once the main loop becomes idle (after the current batch of events
7565  * has been processed, roughly).
7566  *
7567  * Applications rarely need to call this, as redraws are handled
7568  * automatically by modification functions.
7569  *
7570  * This function will not do anything if @self is not visible, or
7571  * if the actor is inside an invisible part of the scenegraph.
7572  *
7573  * Also be aware that painting is a NOP for actors with an opacity of
7574  * 0
7575  *
7576  * When you are implementing a custom actor you must queue a redraw
7577  * whenever some private state changes that will affect painting or
7578  * picking of your actor.
7579  */
7580 void
7581 clutter_actor_queue_redraw (ClutterActor *self)
7582 {
7583   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7584
7585   _clutter_actor_queue_redraw_full (self,
7586                                     0, /* flags */
7587                                     NULL, /* clip volume */
7588                                     NULL /* effect */);
7589 }
7590
7591 /*< private >
7592  * _clutter_actor_queue_redraw_with_clip:
7593  * @self: A #ClutterActor
7594  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7595  *   this queue redraw.
7596  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7597  *   redrawn or %NULL if you are just using a @flag to state your
7598  *   desired clipping.
7599  *
7600  * Queues up a clipped redraw of an actor and any children. The redraw
7601  * occurs once the main loop becomes idle (after the current batch of
7602  * events has been processed, roughly).
7603  *
7604  * If no flags are given the clip volume is defined by @volume
7605  * specified in actor coordinates and tells Clutter that only content
7606  * within this volume has been changed so Clutter can optionally
7607  * optimize the redraw.
7608  *
7609  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7610  * should be %NULL and this tells Clutter to use the actor's current
7611  * allocation as a clip box. This flag can only be used for 2D actors,
7612  * because any actor with depth may be projected outside its
7613  * allocation.
7614  *
7615  * Applications rarely need to call this, as redraws are handled
7616  * automatically by modification functions.
7617  *
7618  * This function will not do anything if @self is not visible, or if
7619  * the actor is inside an invisible part of the scenegraph.
7620  *
7621  * Also be aware that painting is a NOP for actors with an opacity of
7622  * 0
7623  *
7624  * When you are implementing a custom actor you must queue a redraw
7625  * whenever some private state changes that will affect painting or
7626  * picking of your actor.
7627  */
7628 void
7629 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7630                                        ClutterRedrawFlags  flags,
7631                                        ClutterPaintVolume *volume)
7632 {
7633   _clutter_actor_queue_redraw_full (self,
7634                                     flags, /* flags */
7635                                     volume, /* clip volume */
7636                                     NULL /* effect */);
7637 }
7638
7639 static void
7640 _clutter_actor_queue_only_relayout (ClutterActor *self)
7641 {
7642   ClutterActorPrivate *priv = self->priv;
7643
7644   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7645     return;
7646
7647   if (priv->needs_width_request &&
7648       priv->needs_height_request &&
7649       priv->needs_allocation)
7650     return; /* save some cpu cycles */
7651
7652 #if CLUTTER_ENABLE_DEBUG
7653   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7654     {
7655       g_warning ("The actor '%s' is currently inside an allocation "
7656                  "cycle; calling clutter_actor_queue_relayout() is "
7657                  "not recommended",
7658                  _clutter_actor_get_debug_name (self));
7659     }
7660 #endif /* CLUTTER_ENABLE_DEBUG */
7661
7662   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7663 }
7664
7665 /**
7666  * clutter_actor_queue_redraw_with_clip:
7667  * @self: a #ClutterActor
7668  * @clip: (allow-none): a rectangular clip region, or %NULL
7669  *
7670  * Queues a redraw on @self limited to a specific, actor-relative
7671  * rectangular area.
7672  *
7673  * If @clip is %NULL this function is equivalent to
7674  * clutter_actor_queue_redraw().
7675  *
7676  * Since: 1.10
7677  */
7678 void
7679 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7680                                       const cairo_rectangle_int_t *clip)
7681 {
7682   ClutterPaintVolume volume;
7683   ClutterVertex origin;
7684
7685   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7686
7687   if (clip == NULL)
7688     {
7689       clutter_actor_queue_redraw (self);
7690       return;
7691     }
7692
7693   _clutter_paint_volume_init_static (&volume, self);
7694
7695   origin.x = clip->x;
7696   origin.y = clip->y;
7697   origin.z = 0.0f;
7698
7699   clutter_paint_volume_set_origin (&volume, &origin);
7700   clutter_paint_volume_set_width (&volume, clip->width);
7701   clutter_paint_volume_set_height (&volume, clip->height);
7702
7703   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7704
7705   clutter_paint_volume_free (&volume);
7706 }
7707
7708 /**
7709  * clutter_actor_queue_relayout:
7710  * @self: A #ClutterActor
7711  *
7712  * Indicates that the actor's size request or other layout-affecting
7713  * properties may have changed. This function is used inside #ClutterActor
7714  * subclass implementations, not by applications directly.
7715  *
7716  * Queueing a new layout automatically queues a redraw as well.
7717  *
7718  * Since: 0.8
7719  */
7720 void
7721 clutter_actor_queue_relayout (ClutterActor *self)
7722 {
7723   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7724
7725   _clutter_actor_queue_only_relayout (self);
7726   clutter_actor_queue_redraw (self);
7727 }
7728
7729 /**
7730  * clutter_actor_get_preferred_size:
7731  * @self: a #ClutterActor
7732  * @min_width_p: (out) (allow-none): return location for the minimum
7733  *   width, or %NULL
7734  * @min_height_p: (out) (allow-none): return location for the minimum
7735  *   height, or %NULL
7736  * @natural_width_p: (out) (allow-none): return location for the natural
7737  *   width, or %NULL
7738  * @natural_height_p: (out) (allow-none): return location for the natural
7739  *   height, or %NULL
7740  *
7741  * Computes the preferred minimum and natural size of an actor, taking into
7742  * account the actor's geometry management (either height-for-width
7743  * or width-for-height).
7744  *
7745  * The width and height used to compute the preferred height and preferred
7746  * width are the actor's natural ones.
7747  *
7748  * If you need to control the height for the preferred width, or the width for
7749  * the preferred height, you should use clutter_actor_get_preferred_width()
7750  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7751  * geometry management using the #ClutterActor:request-mode property.
7752  *
7753  * Since: 0.8
7754  */
7755 void
7756 clutter_actor_get_preferred_size (ClutterActor *self,
7757                                   gfloat       *min_width_p,
7758                                   gfloat       *min_height_p,
7759                                   gfloat       *natural_width_p,
7760                                   gfloat       *natural_height_p)
7761 {
7762   ClutterActorPrivate *priv;
7763   gfloat min_width, min_height;
7764   gfloat natural_width, natural_height;
7765
7766   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7767
7768   priv = self->priv;
7769
7770   min_width = min_height = 0;
7771   natural_width = natural_height = 0;
7772
7773   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7774     {
7775       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7776       clutter_actor_get_preferred_width (self, -1,
7777                                          &min_width,
7778                                          &natural_width);
7779       clutter_actor_get_preferred_height (self, natural_width,
7780                                           &min_height,
7781                                           &natural_height);
7782     }
7783   else
7784     {
7785       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7786       clutter_actor_get_preferred_height (self, -1,
7787                                           &min_height,
7788                                           &natural_height);
7789       clutter_actor_get_preferred_width (self, natural_height,
7790                                          &min_width,
7791                                          &natural_width);
7792     }
7793
7794   if (min_width_p)
7795     *min_width_p = min_width;
7796
7797   if (min_height_p)
7798     *min_height_p = min_height;
7799
7800   if (natural_width_p)
7801     *natural_width_p = natural_width;
7802
7803   if (natural_height_p)
7804     *natural_height_p = natural_height;
7805 }
7806
7807 /*< private >
7808  * effective_align:
7809  * @align: a #ClutterActorAlign
7810  * @direction: a #ClutterTextDirection
7811  *
7812  * Retrieves the correct alignment depending on the text direction
7813  *
7814  * Return value: the effective alignment
7815  */
7816 static ClutterActorAlign
7817 effective_align (ClutterActorAlign    align,
7818                  ClutterTextDirection direction)
7819 {
7820   ClutterActorAlign res;
7821
7822   switch (align)
7823     {
7824     case CLUTTER_ACTOR_ALIGN_START:
7825       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7826           ? CLUTTER_ACTOR_ALIGN_END
7827           : CLUTTER_ACTOR_ALIGN_START;
7828       break;
7829
7830     case CLUTTER_ACTOR_ALIGN_END:
7831       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7832           ? CLUTTER_ACTOR_ALIGN_START
7833           : CLUTTER_ACTOR_ALIGN_END;
7834       break;
7835
7836     default:
7837       res = align;
7838       break;
7839     }
7840
7841   return res;
7842 }
7843
7844 static inline void
7845 adjust_for_margin (float  margin_start,
7846                    float  margin_end,
7847                    float *minimum_size,
7848                    float *natural_size,
7849                    float *allocated_start,
7850                    float *allocated_end)
7851 {
7852   *minimum_size -= (margin_start + margin_end);
7853   *natural_size -= (margin_start + margin_end);
7854   *allocated_start += margin_start;
7855   *allocated_end -= margin_end;
7856 }
7857
7858 static inline void
7859 adjust_for_alignment (ClutterActorAlign  alignment,
7860                       float              natural_size,
7861                       float             *allocated_start,
7862                       float             *allocated_end)
7863 {
7864   float allocated_size = *allocated_end - *allocated_start;
7865
7866   switch (alignment)
7867     {
7868     case CLUTTER_ACTOR_ALIGN_FILL:
7869       /* do nothing */
7870       break;
7871
7872     case CLUTTER_ACTOR_ALIGN_START:
7873       /* keep start */
7874       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7875       break;
7876
7877     case CLUTTER_ACTOR_ALIGN_END:
7878       if (allocated_size > natural_size)
7879         {
7880           *allocated_start += (allocated_size - natural_size);
7881           *allocated_end = *allocated_start + natural_size;
7882         }
7883       break;
7884
7885     case CLUTTER_ACTOR_ALIGN_CENTER:
7886       if (allocated_size > natural_size)
7887         {
7888           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7889           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7890         }
7891       break;
7892     }
7893 }
7894
7895 /*< private >
7896  * clutter_actor_adjust_width:
7897  * @self: a #ClutterActor
7898  * @minimum_width: (inout): the actor's preferred minimum width, which
7899  *   will be adjusted depending on the margin
7900  * @natural_width: (inout): the actor's preferred natural width, which
7901  *   will be adjusted depending on the margin
7902  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7903  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7904  *
7905  * Adjusts the preferred and allocated position and size of an actor,
7906  * depending on the margin and alignment properties.
7907  */
7908 static void
7909 clutter_actor_adjust_width (ClutterActor *self,
7910                             gfloat       *minimum_width,
7911                             gfloat       *natural_width,
7912                             gfloat       *adjusted_x1,
7913                             gfloat       *adjusted_x2)
7914 {
7915   ClutterTextDirection text_dir;
7916   const ClutterLayoutInfo *info;
7917
7918   info = _clutter_actor_get_layout_info_or_defaults (self);
7919   text_dir = clutter_actor_get_text_direction (self);
7920
7921   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7922
7923   /* this will tweak natural_width to remove the margin, so that
7924    * adjust_for_alignment() will use the correct size
7925    */
7926   adjust_for_margin (info->margin.left, info->margin.right,
7927                      minimum_width, natural_width,
7928                      adjusted_x1, adjusted_x2);
7929
7930   adjust_for_alignment (effective_align (info->x_align, text_dir),
7931                         *natural_width,
7932                         adjusted_x1, adjusted_x2);
7933 }
7934
7935 /*< private >
7936  * clutter_actor_adjust_height:
7937  * @self: a #ClutterActor
7938  * @minimum_height: (inout): the actor's preferred minimum height, which
7939  *   will be adjusted depending on the margin
7940  * @natural_height: (inout): the actor's preferred natural height, which
7941  *   will be adjusted depending on the margin
7942  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7943  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7944  *
7945  * Adjusts the preferred and allocated position and size of an actor,
7946  * depending on the margin and alignment properties.
7947  */
7948 static void
7949 clutter_actor_adjust_height (ClutterActor *self,
7950                              gfloat       *minimum_height,
7951                              gfloat       *natural_height,
7952                              gfloat       *adjusted_y1,
7953                              gfloat       *adjusted_y2)
7954 {
7955   const ClutterLayoutInfo *info;
7956
7957   info = _clutter_actor_get_layout_info_or_defaults (self);
7958
7959   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7960
7961   /* this will tweak natural_height to remove the margin, so that
7962    * adjust_for_alignment() will use the correct size
7963    */
7964   adjust_for_margin (info->margin.top, info->margin.bottom,
7965                      minimum_height, natural_height,
7966                      adjusted_y1,
7967                      adjusted_y2);
7968
7969   /* we don't use effective_align() here, because text direction
7970    * only affects the horizontal axis
7971    */
7972   adjust_for_alignment (info->y_align,
7973                         *natural_height,
7974                         adjusted_y1,
7975                         adjusted_y2);
7976
7977 }
7978
7979 /* looks for a cached size request for this for_size. If not
7980  * found, returns the oldest entry so it can be overwritten */
7981 static gboolean
7982 _clutter_actor_get_cached_size_request (gfloat         for_size,
7983                                         SizeRequest   *cached_size_requests,
7984                                         SizeRequest  **result)
7985 {
7986   guint i;
7987
7988   *result = &cached_size_requests[0];
7989
7990   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7991     {
7992       SizeRequest *sr;
7993
7994       sr = &cached_size_requests[i];
7995
7996       if (sr->age > 0 &&
7997           sr->for_size == for_size)
7998         {
7999           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
8000           *result = sr;
8001           return TRUE;
8002         }
8003       else if (sr->age < (*result)->age)
8004         {
8005           *result = sr;
8006         }
8007     }
8008
8009   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8010
8011   return FALSE;
8012 }
8013
8014 /**
8015  * clutter_actor_get_preferred_width:
8016  * @self: A #ClutterActor
8017  * @for_height: available height when computing the preferred width,
8018  *   or a negative value to indicate that no height is defined
8019  * @min_width_p: (out) (allow-none): return location for minimum width,
8020  *   or %NULL
8021  * @natural_width_p: (out) (allow-none): return location for the natural
8022  *   width, or %NULL
8023  *
8024  * Computes the requested minimum and natural widths for an actor,
8025  * optionally depending on the specified height, or if they are
8026  * already computed, returns the cached values.
8027  *
8028  * An actor may not get its request - depending on the layout
8029  * manager that's in effect.
8030  *
8031  * A request should not incorporate the actor's scale or anchor point;
8032  * those transformations do not affect layout, only rendering.
8033  *
8034  * Since: 0.8
8035  */
8036 void
8037 clutter_actor_get_preferred_width (ClutterActor *self,
8038                                    gfloat        for_height,
8039                                    gfloat       *min_width_p,
8040                                    gfloat       *natural_width_p)
8041 {
8042   float request_min_width, request_natural_width;
8043   SizeRequest *cached_size_request;
8044   const ClutterLayoutInfo *info;
8045   ClutterActorPrivate *priv;
8046   gboolean found_in_cache;
8047
8048   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8049
8050   priv = self->priv;
8051
8052   info = _clutter_actor_get_layout_info_or_defaults (self);
8053
8054   /* we shortcircuit the case of a fixed size set using set_width() */
8055   if (priv->min_width_set && priv->natural_width_set)
8056     {
8057       if (min_width_p != NULL)
8058         *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8059
8060       if (natural_width_p != NULL)
8061         *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8062
8063       return;
8064     }
8065
8066   /* the remaining cases are:
8067    *
8068    *   - either min_width or natural_width have been set
8069    *   - neither min_width or natural_width have been set
8070    *
8071    * in both cases, we go through the cache (and through the actor in case
8072    * of cache misses) and determine the authoritative value depending on
8073    * the *_set flags.
8074    */
8075
8076   if (!priv->needs_width_request)
8077     {
8078       found_in_cache =
8079         _clutter_actor_get_cached_size_request (for_height,
8080                                                 priv->width_requests,
8081                                                 &cached_size_request);
8082     }
8083   else
8084     {
8085       /* if the actor needs a width request we use the first slot */
8086       found_in_cache = FALSE;
8087       cached_size_request = &priv->width_requests[0];
8088     }
8089
8090   if (!found_in_cache)
8091     {
8092       gfloat minimum_width, natural_width;
8093       ClutterActorClass *klass;
8094
8095       minimum_width = natural_width = 0;
8096
8097       /* adjust for the margin */
8098       if (for_height >= 0)
8099         {
8100           for_height -= (info->margin.top + info->margin.bottom);
8101           if (for_height < 0)
8102             for_height = 0;
8103         }
8104
8105       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8106
8107       klass = CLUTTER_ACTOR_GET_CLASS (self);
8108       klass->get_preferred_width (self, for_height,
8109                                   &minimum_width,
8110                                   &natural_width);
8111
8112       /* adjust for the margin */
8113       minimum_width += (info->margin.left + info->margin.right);
8114       natural_width += (info->margin.left + info->margin.right);
8115
8116       /* Due to accumulated float errors, it's better not to warn
8117        * on this, but just fix it.
8118        */
8119       if (natural_width < minimum_width)
8120         natural_width = minimum_width;
8121
8122       cached_size_request->min_size = minimum_width;
8123       cached_size_request->natural_size = natural_width;
8124       cached_size_request->for_size = for_height;
8125       cached_size_request->age = priv->cached_width_age;
8126
8127       priv->cached_width_age += 1;
8128       priv->needs_width_request = FALSE;
8129     }
8130
8131   if (!priv->min_width_set)
8132     request_min_width = cached_size_request->min_size;
8133   else
8134     request_min_width = info->minimum.width;
8135
8136   if (!priv->natural_width_set)
8137     request_natural_width = cached_size_request->natural_size;
8138   else
8139     request_natural_width = info->natural.width;
8140
8141   if (min_width_p)
8142     *min_width_p = request_min_width;
8143
8144   if (natural_width_p)
8145     *natural_width_p = request_natural_width;
8146 }
8147
8148 /**
8149  * clutter_actor_get_preferred_height:
8150  * @self: A #ClutterActor
8151  * @for_width: available width to assume in computing desired height,
8152  *   or a negative value to indicate that no width is defined
8153  * @min_height_p: (out) (allow-none): return location for minimum height,
8154  *   or %NULL
8155  * @natural_height_p: (out) (allow-none): return location for natural
8156  *   height, or %NULL
8157  *
8158  * Computes the requested minimum and natural heights for an actor,
8159  * or if they are already computed, returns the cached values.
8160  *
8161  * An actor may not get its request - depending on the layout
8162  * manager that's in effect.
8163  *
8164  * A request should not incorporate the actor's scale or anchor point;
8165  * those transformations do not affect layout, only rendering.
8166  *
8167  * Since: 0.8
8168  */
8169 void
8170 clutter_actor_get_preferred_height (ClutterActor *self,
8171                                     gfloat        for_width,
8172                                     gfloat       *min_height_p,
8173                                     gfloat       *natural_height_p)
8174 {
8175   float request_min_height, request_natural_height;
8176   SizeRequest *cached_size_request;
8177   const ClutterLayoutInfo *info;
8178   ClutterActorPrivate *priv;
8179   gboolean found_in_cache;
8180
8181   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8182
8183   priv = self->priv;
8184
8185   info = _clutter_actor_get_layout_info_or_defaults (self);
8186
8187   /* we shortcircuit the case of a fixed size set using set_height() */
8188   if (priv->min_height_set && priv->natural_height_set)
8189     {
8190       if (min_height_p != NULL)
8191         *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8192
8193       if (natural_height_p != NULL)
8194         *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8195
8196       return;
8197     }
8198
8199   /* the remaining cases are:
8200    *
8201    *   - either min_height or natural_height have been set
8202    *   - neither min_height or natural_height have been set
8203    *
8204    * in both cases, we go through the cache (and through the actor in case
8205    * of cache misses) and determine the authoritative value depending on
8206    * the *_set flags.
8207    */
8208
8209   if (!priv->needs_height_request)
8210     {
8211       found_in_cache =
8212         _clutter_actor_get_cached_size_request (for_width,
8213                                                 priv->height_requests,
8214                                                 &cached_size_request);
8215     }
8216   else
8217     {
8218       found_in_cache = FALSE;
8219       cached_size_request = &priv->height_requests[0];
8220     }
8221
8222   if (!found_in_cache)
8223     {
8224       gfloat minimum_height, natural_height;
8225       ClutterActorClass *klass;
8226
8227       minimum_height = natural_height = 0;
8228
8229       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8230
8231       /* adjust for margin */
8232       if (for_width >= 0)
8233         {
8234           for_width -= (info->margin.left + info->margin.right);
8235           if (for_width < 0)
8236             for_width = 0;
8237         }
8238
8239       klass = CLUTTER_ACTOR_GET_CLASS (self);
8240       klass->get_preferred_height (self, for_width,
8241                                    &minimum_height,
8242                                    &natural_height);
8243
8244       /* adjust for margin */
8245       minimum_height += (info->margin.top + info->margin.bottom);
8246       natural_height += (info->margin.top + info->margin.bottom);
8247
8248       /* Due to accumulated float errors, it's better not to warn
8249        * on this, but just fix it.
8250        */
8251       if (natural_height < minimum_height)
8252         natural_height = minimum_height;
8253
8254       cached_size_request->min_size = minimum_height;
8255       cached_size_request->natural_size = natural_height;
8256       cached_size_request->for_size = for_width;
8257       cached_size_request->age = priv->cached_height_age;
8258
8259       priv->cached_height_age += 1;
8260       priv->needs_height_request = FALSE;
8261     }
8262
8263   if (!priv->min_height_set)
8264     request_min_height = cached_size_request->min_size;
8265   else
8266     request_min_height = info->minimum.height;
8267
8268   if (!priv->natural_height_set)
8269     request_natural_height = cached_size_request->natural_size;
8270   else
8271     request_natural_height = info->natural.height;
8272
8273   if (min_height_p)
8274     *min_height_p = request_min_height;
8275
8276   if (natural_height_p)
8277     *natural_height_p = request_natural_height;
8278 }
8279
8280 /**
8281  * clutter_actor_get_allocation_box:
8282  * @self: A #ClutterActor
8283  * @box: (out): the function fills this in with the actor's allocation
8284  *
8285  * Gets the layout box an actor has been assigned. The allocation can
8286  * only be assumed valid inside a paint() method; anywhere else, it
8287  * may be out-of-date.
8288  *
8289  * An allocation does not incorporate the actor's scale or anchor point;
8290  * those transformations do not affect layout, only rendering.
8291  *
8292  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8293  * of functions inside the implementation of the get_preferred_width()
8294  * or get_preferred_height() virtual functions.</note>
8295  *
8296  * Since: 0.8
8297  */
8298 void
8299 clutter_actor_get_allocation_box (ClutterActor    *self,
8300                                   ClutterActorBox *box)
8301 {
8302   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8303
8304   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8305    * which limits calling get_allocation to inside paint() basically; or
8306    * we can 2) force a layout, which could be expensive if someone calls
8307    * get_allocation somewhere silly; or we can 3) just return the latest
8308    * value, allowing it to be out-of-date, and assume people know what
8309    * they are doing.
8310    *
8311    * The least-surprises approach that keeps existing code working is
8312    * likely to be 2). People can end up doing some inefficient things,
8313    * though, and in general code that requires 2) is probably broken.
8314    */
8315
8316   /* this implements 2) */
8317   if (G_UNLIKELY (self->priv->needs_allocation))
8318     {
8319       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8320
8321       /* do not queue a relayout on an unparented actor */
8322       if (stage)
8323         _clutter_stage_maybe_relayout (stage);
8324     }
8325
8326   /* commenting out the code above and just keeping this assigment
8327    * implements 3)
8328    */
8329   *box = self->priv->allocation;
8330 }
8331
8332 /**
8333  * clutter_actor_get_allocation_geometry:
8334  * @self: A #ClutterActor
8335  * @geom: (out): allocation geometry in pixels
8336  *
8337  * Gets the layout box an actor has been assigned.  The allocation can
8338  * only be assumed valid inside a paint() method; anywhere else, it
8339  * may be out-of-date.
8340  *
8341  * An allocation does not incorporate the actor's scale or anchor point;
8342  * those transformations do not affect layout, only rendering.
8343  *
8344  * The returned rectangle is in pixels.
8345  *
8346  * Since: 0.8
8347  */
8348 void
8349 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8350                                        ClutterGeometry *geom)
8351 {
8352   ClutterActorBox box;
8353
8354   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8355   g_return_if_fail (geom != NULL);
8356
8357   clutter_actor_get_allocation_box (self, &box);
8358
8359   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8360   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8361   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8362   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8363 }
8364
8365 static void
8366 clutter_actor_update_constraints (ClutterActor    *self,
8367                                   ClutterActorBox *allocation)
8368 {
8369   ClutterActorPrivate *priv = self->priv;
8370   const GList *constraints, *l;
8371
8372   if (priv->constraints == NULL)
8373     return;
8374
8375   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8376   for (l = constraints; l != NULL; l = l->next)
8377     {
8378       ClutterConstraint *constraint = l->data;
8379       ClutterActorMeta *meta = l->data;
8380
8381       if (clutter_actor_meta_get_enabled (meta))
8382         {
8383           _clutter_constraint_update_allocation (constraint,
8384                                                  self,
8385                                                  allocation);
8386
8387           CLUTTER_NOTE (LAYOUT,
8388                         "Allocation of '%s' after constraint '%s': "
8389                         "{ %.2f, %.2f, %.2f, %.2f }",
8390                         _clutter_actor_get_debug_name (self),
8391                         _clutter_actor_meta_get_debug_name (meta),
8392                         allocation->x1,
8393                         allocation->y1,
8394                         allocation->x2,
8395                         allocation->y2);
8396         }
8397     }
8398 }
8399
8400 /*< private >
8401  * clutter_actor_adjust_allocation:
8402  * @self: a #ClutterActor
8403  * @allocation: (inout): the allocation to adjust
8404  *
8405  * Adjusts the passed allocation box taking into account the actor's
8406  * layout information, like alignment, expansion, and margin.
8407  */
8408 static void
8409 clutter_actor_adjust_allocation (ClutterActor    *self,
8410                                  ClutterActorBox *allocation)
8411 {
8412   ClutterActorBox adj_allocation;
8413   float alloc_width, alloc_height;
8414   float min_width, min_height;
8415   float nat_width, nat_height;
8416   ClutterRequestMode req_mode;
8417
8418   adj_allocation = *allocation;
8419
8420   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8421
8422   /* we want to hit the cache, so we use the public API */
8423   req_mode = clutter_actor_get_request_mode (self);
8424
8425   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8426     {
8427       clutter_actor_get_preferred_width (self, -1,
8428                                          &min_width,
8429                                          &nat_width);
8430       clutter_actor_get_preferred_height (self, alloc_width,
8431                                           &min_height,
8432                                           &nat_height);
8433     }
8434   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8435     {
8436       clutter_actor_get_preferred_height (self, -1,
8437                                           &min_height,
8438                                           &nat_height);
8439       clutter_actor_get_preferred_height (self, alloc_height,
8440                                           &min_width,
8441                                           &nat_width);
8442     }
8443
8444 #ifdef CLUTTER_ENABLE_DEBUG
8445   /* warn about underallocations */
8446   if (_clutter_diagnostic_enabled () &&
8447       (floorf (min_width - alloc_width) > 0 ||
8448        floorf (min_height - alloc_height) > 0))
8449     {
8450       ClutterActor *parent = clutter_actor_get_parent (self);
8451
8452       /* the only actors that are allowed to be underallocated are the Stage,
8453        * as it doesn't have an implicit size, and Actors that specifically
8454        * told us that they want to opt-out from layout control mechanisms
8455        * through the NO_LAYOUT escape hatch.
8456        */
8457       if (parent != NULL &&
8458           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8459         {
8460           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8461                      "of %.2f x %.2f from its parent actor '%s', but its "
8462                      "requested minimum size is of %.2f x %.2f",
8463                      _clutter_actor_get_debug_name (self),
8464                      alloc_width, alloc_height,
8465                      _clutter_actor_get_debug_name (parent),
8466                      min_width, min_height);
8467         }
8468     }
8469 #endif
8470
8471   clutter_actor_adjust_width (self,
8472                               &min_width,
8473                               &nat_width,
8474                               &adj_allocation.x1,
8475                               &adj_allocation.x2);
8476
8477   clutter_actor_adjust_height (self,
8478                                &min_height,
8479                                &nat_height,
8480                                &adj_allocation.y1,
8481                                &adj_allocation.y2);
8482
8483   /* we maintain the invariant that an allocation cannot be adjusted
8484    * to be outside the parent-given box
8485    */
8486   if (adj_allocation.x1 < allocation->x1 ||
8487       adj_allocation.y1 < allocation->y1 ||
8488       adj_allocation.x2 > allocation->x2 ||
8489       adj_allocation.y2 > allocation->y2)
8490     {
8491       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8492                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8493                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8494                  _clutter_actor_get_debug_name (self),
8495                  adj_allocation.x1, adj_allocation.y1,
8496                  adj_allocation.x2 - adj_allocation.x1,
8497                  adj_allocation.y2 - adj_allocation.y1,
8498                  allocation->x1, allocation->y1,
8499                  allocation->x2 - allocation->x1,
8500                  allocation->y2 - allocation->y1);
8501       return;
8502     }
8503
8504   *allocation = adj_allocation;
8505 }
8506
8507 /**
8508  * clutter_actor_allocate:
8509  * @self: A #ClutterActor
8510  * @box: new allocation of the actor, in parent-relative coordinates
8511  * @flags: flags that control the allocation
8512  *
8513  * Called by the parent of an actor to assign the actor its size.
8514  * Should never be called by applications (except when implementing
8515  * a container or layout manager).
8516  *
8517  * Actors can know from their allocation box whether they have moved
8518  * with respect to their parent actor. The @flags parameter describes
8519  * additional information about the allocation, for instance whether
8520  * the parent has moved with respect to the stage, for example because
8521  * a grandparent's origin has moved.
8522  *
8523  * Since: 0.8
8524  */
8525 void
8526 clutter_actor_allocate (ClutterActor           *self,
8527                         const ClutterActorBox  *box,
8528                         ClutterAllocationFlags  flags)
8529 {
8530   ClutterActorPrivate *priv;
8531   ClutterActorClass *klass;
8532   ClutterActorBox old_allocation, real_allocation;
8533   gboolean origin_changed, child_moved, size_changed;
8534   gboolean stage_allocation_changed;
8535
8536   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8537   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8538     {
8539       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8540                  "which isn't a descendent of the stage!\n",
8541                  self, _clutter_actor_get_debug_name (self));
8542       return;
8543     }
8544
8545   priv = self->priv;
8546
8547   old_allocation = priv->allocation;
8548   real_allocation = *box;
8549
8550   /* constraints are allowed to modify the allocation only here; we do
8551    * this prior to all the other checks so that we can bail out if the
8552    * allocation did not change
8553    */
8554   clutter_actor_update_constraints (self, &real_allocation);
8555
8556   /* adjust the allocation depending on the align/margin properties */
8557   clutter_actor_adjust_allocation (self, &real_allocation);
8558
8559   if (real_allocation.x2 < real_allocation.x1 ||
8560       real_allocation.y2 < real_allocation.y1)
8561     {
8562       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8563                  _clutter_actor_get_debug_name (self),
8564                  real_allocation.x2 - real_allocation.x1,
8565                  real_allocation.y2 - real_allocation.y1);
8566     }
8567
8568   /* we allow 0-sized actors, but not negative-sized ones */
8569   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8570   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8571
8572   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8573
8574   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8575                  real_allocation.y1 != old_allocation.y1);
8576
8577   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8578                   real_allocation.y2 != old_allocation.y2);
8579
8580   if (origin_changed || child_moved || size_changed)
8581     stage_allocation_changed = TRUE;
8582   else
8583     stage_allocation_changed = FALSE;
8584
8585   /* If we get an allocation "out of the blue"
8586    * (we did not queue relayout), then we want to
8587    * ignore it. But if we have needs_allocation set,
8588    * we want to guarantee that allocate() virtual
8589    * method is always called, i.e. that queue_relayout()
8590    * always results in an allocate() invocation on
8591    * an actor.
8592    *
8593    * The optimization here is to avoid re-allocating
8594    * actors that did not queue relayout and were
8595    * not moved.
8596    */
8597   if (!priv->needs_allocation && !stage_allocation_changed)
8598     {
8599       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8600       return;
8601     }
8602
8603   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8604    * clutter_actor_allocate(), it indicates whether the parent has its
8605    * absolute origin moved; when passed in to ClutterActor::allocate()
8606    * virtual method though, it indicates whether the child has its
8607    * absolute origin moved.  So we set it when child_moved is TRUE
8608    */
8609   if (child_moved)
8610     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8611
8612   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8613
8614   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8615                 _clutter_actor_get_debug_name (self));
8616
8617   klass = CLUTTER_ACTOR_GET_CLASS (self);
8618   klass->allocate (self, &real_allocation, flags);
8619
8620   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8621
8622   if (stage_allocation_changed)
8623     clutter_actor_queue_redraw (self);
8624 }
8625
8626 /**
8627  * clutter_actor_set_allocation:
8628  * @self: a #ClutterActor
8629  * @box: a #ClutterActorBox
8630  * @flags: allocation flags
8631  *
8632  * Stores the allocation of @self as defined by @box.
8633  *
8634  * This function can only be called from within the implementation of
8635  * the #ClutterActorClass.allocate() virtual function.
8636  *
8637  * The allocation should have been adjusted to take into account constraints,
8638  * alignment, and margin properties. If you are implementing a #ClutterActor
8639  * subclass that provides its own layout management policy for its children
8640  * instead of using a #ClutterLayoutManager delegate, you should not call
8641  * this function on the children of @self; instead, you should call
8642  * clutter_actor_allocate(), which will adjust the allocation box for
8643  * you.
8644  *
8645  * This function should only be used by subclasses of #ClutterActor
8646  * that wish to store their allocation but cannot chain up to the
8647  * parent's implementation; the default implementation of the
8648  * #ClutterActorClass.allocate() virtual function will call this
8649  * function.
8650  *
8651  * It is important to note that, while chaining up was the recommended
8652  * behaviour for #ClutterActor subclasses prior to the introduction of
8653  * this function, it is recommended to call clutter_actor_set_allocation()
8654  * instead.
8655  *
8656  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8657  * to handle the allocation of its children, this function will call
8658  * the clutter_layout_manager_allocate() function only if the
8659  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8660  * expected that the subclass will call clutter_layout_manager_allocate()
8661  * by itself. For instance, the following code:
8662  *
8663  * |[
8664  * static void
8665  * my_actor_allocate (ClutterActor *actor,
8666  *                    const ClutterActorBox *allocation,
8667  *                    ClutterAllocationFlags flags)
8668  * {
8669  *   ClutterActorBox new_alloc;
8670  *   ClutterAllocationFlags new_flags;
8671  *
8672  *   adjust_allocation (allocation, &amp;new_alloc);
8673  *
8674  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8675  *
8676  *   /&ast; this will use the layout manager set on the actor &ast;/
8677  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8678  * }
8679  * ]|
8680  *
8681  * is equivalent to this:
8682  *
8683  * |[
8684  * static void
8685  * my_actor_allocate (ClutterActor *actor,
8686  *                    const ClutterActorBox *allocation,
8687  *                    ClutterAllocationFlags flags)
8688  * {
8689  *   ClutterLayoutManager *layout;
8690  *   ClutterActorBox new_alloc;
8691  *
8692  *   adjust_allocation (allocation, &amp;new_alloc);
8693  *
8694  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8695  *
8696  *   layout = clutter_actor_get_layout_manager (actor);
8697  *   clutter_layout_manager_allocate (layout,
8698  *                                    CLUTTER_CONTAINER (actor),
8699  *                                    &amp;new_alloc,
8700  *                                    flags);
8701  * }
8702  * ]|
8703  *
8704  * Since: 1.10
8705  */
8706 void
8707 clutter_actor_set_allocation (ClutterActor           *self,
8708                               const ClutterActorBox  *box,
8709                               ClutterAllocationFlags  flags)
8710 {
8711   ClutterActorPrivate *priv;
8712   gboolean changed;
8713
8714   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8715   g_return_if_fail (box != NULL);
8716
8717   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8718     {
8719       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8720                   "can only be called from within the implementation of "
8721                   "the ClutterActor::allocate() virtual function.");
8722       return;
8723     }
8724
8725   priv = self->priv;
8726
8727   g_object_freeze_notify (G_OBJECT (self));
8728
8729   changed = clutter_actor_set_allocation_internal (self, box, flags);
8730
8731   /* we allocate our children before we notify changes in our geometry,
8732    * so that people connecting to properties will be able to get valid
8733    * data out of the sub-tree of the scene graph that has this actor at
8734    * the root.
8735    */
8736   clutter_actor_maybe_layout_children (self, box, flags);
8737
8738   if (changed)
8739     {
8740       ClutterActorBox signal_box = priv->allocation;
8741       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8742
8743       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8744                      &signal_box,
8745                      signal_flags);
8746     }
8747
8748   g_object_thaw_notify (G_OBJECT (self));
8749 }
8750
8751 /**
8752  * clutter_actor_set_geometry:
8753  * @self: A #ClutterActor
8754  * @geometry: A #ClutterGeometry
8755  *
8756  * Sets the actor's fixed position and forces its minimum and natural
8757  * size, in pixels. This means the untransformed actor will have the
8758  * given geometry. This is the same as calling clutter_actor_set_position()
8759  * and clutter_actor_set_size().
8760  *
8761  * Deprecated: 1.10: Use clutter_actor_set_position() and
8762  *   clutter_actor_set_size() instead.
8763  */
8764 void
8765 clutter_actor_set_geometry (ClutterActor          *self,
8766                             const ClutterGeometry *geometry)
8767 {
8768   g_object_freeze_notify (G_OBJECT (self));
8769
8770   clutter_actor_set_position (self, geometry->x, geometry->y);
8771   clutter_actor_set_size (self, geometry->width, geometry->height);
8772
8773   g_object_thaw_notify (G_OBJECT (self));
8774 }
8775
8776 /**
8777  * clutter_actor_get_geometry:
8778  * @self: A #ClutterActor
8779  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8780  *
8781  * Gets the size and position of an actor relative to its parent
8782  * actor. This is the same as calling clutter_actor_get_position() and
8783  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8784  * requested size and position if the actor's allocation is invalid.
8785  *
8786  * Deprecated: 1.10: Use clutter_actor_get_position() and
8787  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8788  *   instead.
8789  */
8790 void
8791 clutter_actor_get_geometry (ClutterActor    *self,
8792                             ClutterGeometry *geometry)
8793 {
8794   gfloat x, y, width, height;
8795
8796   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8797   g_return_if_fail (geometry != NULL);
8798
8799   clutter_actor_get_position (self, &x, &y);
8800   clutter_actor_get_size (self, &width, &height);
8801
8802   geometry->x = (int) x;
8803   geometry->y = (int) y;
8804   geometry->width = (int) width;
8805   geometry->height = (int) height;
8806 }
8807
8808 /**
8809  * clutter_actor_set_position:
8810  * @self: A #ClutterActor
8811  * @x: New left position of actor in pixels.
8812  * @y: New top position of actor in pixels.
8813  *
8814  * Sets the actor's fixed position in pixels relative to any parent
8815  * actor.
8816  *
8817  * If a layout manager is in use, this position will override the
8818  * layout manager and force a fixed position.
8819  */
8820 void
8821 clutter_actor_set_position (ClutterActor *self,
8822                             gfloat        x,
8823                             gfloat        y)
8824 {
8825   ClutterPoint new_position;
8826
8827   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8828
8829   clutter_point_init (&new_position, x, y);
8830
8831   if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
8832     {
8833       ClutterPoint cur_position;
8834
8835       cur_position.x = clutter_actor_get_x (self);
8836       cur_position.y = clutter_actor_get_y (self);
8837
8838       _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
8839                                         &cur_position,
8840                                         &new_position);
8841     }
8842   else
8843     _clutter_actor_update_transition (self,
8844                                       obj_props[PROP_POSITION],
8845                                       &new_position);
8846
8847   clutter_actor_queue_relayout (self);
8848 }
8849
8850 /**
8851  * clutter_actor_get_fixed_position_set:
8852  * @self: A #ClutterActor
8853  *
8854  * Checks whether an actor has a fixed position set (and will thus be
8855  * unaffected by any layout manager).
8856  *
8857  * Return value: %TRUE if the fixed position is set on the actor
8858  *
8859  * Since: 0.8
8860  */
8861 gboolean
8862 clutter_actor_get_fixed_position_set (ClutterActor *self)
8863 {
8864   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8865
8866   return self->priv->position_set;
8867 }
8868
8869 /**
8870  * clutter_actor_set_fixed_position_set:
8871  * @self: A #ClutterActor
8872  * @is_set: whether to use fixed position
8873  *
8874  * Sets whether an actor has a fixed position set (and will thus be
8875  * unaffected by any layout manager).
8876  *
8877  * Since: 0.8
8878  */
8879 void
8880 clutter_actor_set_fixed_position_set (ClutterActor *self,
8881                                       gboolean      is_set)
8882 {
8883   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8884
8885   if (self->priv->position_set == (is_set != FALSE))
8886     return;
8887
8888   self->priv->position_set = is_set != FALSE;
8889   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8890
8891   clutter_actor_queue_relayout (self);
8892 }
8893
8894 /**
8895  * clutter_actor_move_by:
8896  * @self: A #ClutterActor
8897  * @dx: Distance to move Actor on X axis.
8898  * @dy: Distance to move Actor on Y axis.
8899  *
8900  * Moves an actor by the specified distance relative to its current
8901  * position in pixels.
8902  *
8903  * This function modifies the fixed position of an actor and thus removes
8904  * it from any layout management. Another way to move an actor is with an
8905  * anchor point, see clutter_actor_set_anchor_point().
8906  *
8907  * Since: 0.2
8908  */
8909 void
8910 clutter_actor_move_by (ClutterActor *self,
8911                        gfloat        dx,
8912                        gfloat        dy)
8913 {
8914   const ClutterLayoutInfo *info;
8915   gfloat x, y;
8916
8917   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8918
8919   info = _clutter_actor_get_layout_info_or_defaults (self);
8920   x = info->fixed_pos.x;
8921   y = info->fixed_pos.y;
8922
8923   clutter_actor_set_position (self, x + dx, y + dy);
8924 }
8925
8926 static void
8927 clutter_actor_set_min_width (ClutterActor *self,
8928                              gfloat        min_width)
8929 {
8930   ClutterActorPrivate *priv = self->priv;
8931   ClutterActorBox old = { 0, };
8932   ClutterLayoutInfo *info;
8933
8934   /* if we are setting the size on a top-level actor and the
8935    * backend only supports static top-levels (e.g. framebuffers)
8936    * then we ignore the passed value and we override it with
8937    * the stage implementation's preferred size.
8938    */
8939   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8940       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8941     return;
8942
8943   info = _clutter_actor_get_layout_info (self);
8944
8945   if (priv->min_width_set && min_width == info->minimum.width)
8946     return;
8947
8948   g_object_freeze_notify (G_OBJECT (self));
8949
8950   clutter_actor_store_old_geometry (self, &old);
8951
8952   info->minimum.width = min_width;
8953   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8954   clutter_actor_set_min_width_set (self, TRUE);
8955
8956   clutter_actor_notify_if_geometry_changed (self, &old);
8957
8958   g_object_thaw_notify (G_OBJECT (self));
8959
8960   clutter_actor_queue_relayout (self);
8961 }
8962
8963 static void
8964 clutter_actor_set_min_height (ClutterActor *self,
8965                               gfloat        min_height)
8966
8967 {
8968   ClutterActorPrivate *priv = self->priv;
8969   ClutterActorBox old = { 0, };
8970   ClutterLayoutInfo *info;
8971
8972   /* if we are setting the size on a top-level actor and the
8973    * backend only supports static top-levels (e.g. framebuffers)
8974    * then we ignore the passed value and we override it with
8975    * the stage implementation's preferred size.
8976    */
8977   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8978       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8979     return;
8980
8981   info = _clutter_actor_get_layout_info (self);
8982
8983   if (priv->min_height_set && min_height == info->minimum.height)
8984     return;
8985
8986   g_object_freeze_notify (G_OBJECT (self));
8987
8988   clutter_actor_store_old_geometry (self, &old);
8989
8990   info->minimum.height = min_height;
8991   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8992   clutter_actor_set_min_height_set (self, TRUE);
8993
8994   clutter_actor_notify_if_geometry_changed (self, &old);
8995
8996   g_object_thaw_notify (G_OBJECT (self));
8997
8998   clutter_actor_queue_relayout (self);
8999 }
9000
9001 static void
9002 clutter_actor_set_natural_width (ClutterActor *self,
9003                                  gfloat        natural_width)
9004 {
9005   ClutterActorPrivate *priv = self->priv;
9006   ClutterActorBox old = { 0, };
9007   ClutterLayoutInfo *info;
9008
9009   /* if we are setting the size on a top-level actor and the
9010    * backend only supports static top-levels (e.g. framebuffers)
9011    * then we ignore the passed value and we override it with
9012    * the stage implementation's preferred size.
9013    */
9014   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9015       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9016     return;
9017
9018   info = _clutter_actor_get_layout_info (self);
9019
9020   if (priv->natural_width_set && natural_width == info->natural.width)
9021     return;
9022
9023   g_object_freeze_notify (G_OBJECT (self));
9024
9025   clutter_actor_store_old_geometry (self, &old);
9026
9027   info->natural.width = natural_width;
9028   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9029   clutter_actor_set_natural_width_set (self, TRUE);
9030
9031   clutter_actor_notify_if_geometry_changed (self, &old);
9032
9033   g_object_thaw_notify (G_OBJECT (self));
9034
9035   clutter_actor_queue_relayout (self);
9036 }
9037
9038 static void
9039 clutter_actor_set_natural_height (ClutterActor *self,
9040                                   gfloat        natural_height)
9041 {
9042   ClutterActorPrivate *priv = self->priv;
9043   ClutterActorBox old = { 0, };
9044   ClutterLayoutInfo *info;
9045
9046   /* if we are setting the size on a top-level actor and the
9047    * backend only supports static top-levels (e.g. framebuffers)
9048    * then we ignore the passed value and we override it with
9049    * the stage implementation's preferred size.
9050    */
9051   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9052       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9053     return;
9054
9055   info = _clutter_actor_get_layout_info (self);
9056
9057   if (priv->natural_height_set && natural_height == info->natural.height)
9058     return;
9059
9060   g_object_freeze_notify (G_OBJECT (self));
9061
9062   clutter_actor_store_old_geometry (self, &old);
9063
9064   info->natural.height = natural_height;
9065   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9066   clutter_actor_set_natural_height_set (self, TRUE);
9067
9068   clutter_actor_notify_if_geometry_changed (self, &old);
9069
9070   g_object_thaw_notify (G_OBJECT (self));
9071
9072   clutter_actor_queue_relayout (self);
9073 }
9074
9075 static void
9076 clutter_actor_set_min_width_set (ClutterActor *self,
9077                                  gboolean      use_min_width)
9078 {
9079   ClutterActorPrivate *priv = self->priv;
9080   ClutterActorBox old = { 0, };
9081
9082   if (priv->min_width_set == (use_min_width != FALSE))
9083     return;
9084
9085   clutter_actor_store_old_geometry (self, &old);
9086
9087   priv->min_width_set = use_min_width != FALSE;
9088   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9089
9090   clutter_actor_notify_if_geometry_changed (self, &old);
9091
9092   clutter_actor_queue_relayout (self);
9093 }
9094
9095 static void
9096 clutter_actor_set_min_height_set (ClutterActor *self,
9097                                   gboolean      use_min_height)
9098 {
9099   ClutterActorPrivate *priv = self->priv;
9100   ClutterActorBox old = { 0, };
9101
9102   if (priv->min_height_set == (use_min_height != FALSE))
9103     return;
9104
9105   clutter_actor_store_old_geometry (self, &old);
9106
9107   priv->min_height_set = use_min_height != FALSE;
9108   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9109
9110   clutter_actor_notify_if_geometry_changed (self, &old);
9111
9112   clutter_actor_queue_relayout (self);
9113 }
9114
9115 static void
9116 clutter_actor_set_natural_width_set (ClutterActor *self,
9117                                      gboolean      use_natural_width)
9118 {
9119   ClutterActorPrivate *priv = self->priv;
9120   ClutterActorBox old = { 0, };
9121
9122   if (priv->natural_width_set == (use_natural_width != FALSE))
9123     return;
9124
9125   clutter_actor_store_old_geometry (self, &old);
9126
9127   priv->natural_width_set = use_natural_width != FALSE;
9128   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9129
9130   clutter_actor_notify_if_geometry_changed (self, &old);
9131
9132   clutter_actor_queue_relayout (self);
9133 }
9134
9135 static void
9136 clutter_actor_set_natural_height_set (ClutterActor *self,
9137                                       gboolean      use_natural_height)
9138 {
9139   ClutterActorPrivate *priv = self->priv;
9140   ClutterActorBox old = { 0, };
9141
9142   if (priv->natural_height_set == (use_natural_height != FALSE))
9143     return;
9144
9145   clutter_actor_store_old_geometry (self, &old);
9146
9147   priv->natural_height_set = use_natural_height != FALSE;
9148   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9149
9150   clutter_actor_notify_if_geometry_changed (self, &old);
9151
9152   clutter_actor_queue_relayout (self);
9153 }
9154
9155 /**
9156  * clutter_actor_set_request_mode:
9157  * @self: a #ClutterActor
9158  * @mode: the request mode
9159  *
9160  * Sets the geometry request mode of @self.
9161  *
9162  * The @mode determines the order for invoking
9163  * clutter_actor_get_preferred_width() and
9164  * clutter_actor_get_preferred_height()
9165  *
9166  * Since: 1.2
9167  */
9168 void
9169 clutter_actor_set_request_mode (ClutterActor       *self,
9170                                 ClutterRequestMode  mode)
9171 {
9172   ClutterActorPrivate *priv;
9173
9174   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9175
9176   priv = self->priv;
9177
9178   if (priv->request_mode == mode)
9179     return;
9180
9181   priv->request_mode = mode;
9182
9183   priv->needs_width_request = TRUE;
9184   priv->needs_height_request = TRUE;
9185
9186   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9187
9188   clutter_actor_queue_relayout (self);
9189 }
9190
9191 /**
9192  * clutter_actor_get_request_mode:
9193  * @self: a #ClutterActor
9194  *
9195  * Retrieves the geometry request mode of @self
9196  *
9197  * Return value: the request mode for the actor
9198  *
9199  * Since: 1.2
9200  */
9201 ClutterRequestMode
9202 clutter_actor_get_request_mode (ClutterActor *self)
9203 {
9204   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9205                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9206
9207   return self->priv->request_mode;
9208 }
9209
9210 /* variant of set_width() without checks and without notification
9211  * freeze+thaw, for internal usage only
9212  */
9213 static inline void
9214 clutter_actor_set_width_internal (ClutterActor *self,
9215                                   gfloat        width)
9216 {
9217   if (width >= 0)
9218     {
9219       /* the Stage will use the :min-width to control the minimum
9220        * width to be resized to, so we should not be setting it
9221        * along with the :natural-width
9222        */
9223       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9224         clutter_actor_set_min_width (self, width);
9225
9226       clutter_actor_set_natural_width (self, width);
9227     }
9228   else
9229     {
9230       /* we only unset the :natural-width for the Stage */
9231       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9232         clutter_actor_set_min_width_set (self, FALSE);
9233
9234       clutter_actor_set_natural_width_set (self, FALSE);
9235     }
9236 }
9237
9238 /* variant of set_height() without checks and without notification
9239  * freeze+thaw, for internal usage only
9240  */
9241 static inline void
9242 clutter_actor_set_height_internal (ClutterActor *self,
9243                                    gfloat        height)
9244 {
9245   if (height >= 0)
9246     {
9247       /* see the comment above in set_width_internal() */
9248       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9249         clutter_actor_set_min_height (self, height);
9250
9251       clutter_actor_set_natural_height (self, height);
9252     }
9253   else
9254     {
9255       /* see the comment above in set_width_internal() */
9256       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9257         clutter_actor_set_min_height_set (self, FALSE);
9258
9259       clutter_actor_set_natural_height_set (self, FALSE);
9260     }
9261 }
9262
9263 static void
9264 clutter_actor_set_size_internal (ClutterActor      *self,
9265                                  const ClutterSize *size)
9266 {
9267   if (size != NULL)
9268     {
9269       clutter_actor_set_width_internal (self, size->width);
9270       clutter_actor_set_height_internal (self, size->height);
9271     }
9272   else
9273     {
9274       clutter_actor_set_width_internal (self, -1);
9275       clutter_actor_set_height_internal (self, -1);
9276     }
9277 }
9278
9279 /**
9280  * clutter_actor_set_size:
9281  * @self: A #ClutterActor
9282  * @width: New width of actor in pixels, or -1
9283  * @height: New height of actor in pixels, or -1
9284  *
9285  * Sets the actor's size request in pixels. This overrides any
9286  * "normal" size request the actor would have. For example
9287  * a text actor might normally request the size of the text;
9288  * this function would force a specific size instead.
9289  *
9290  * If @width and/or @height are -1 the actor will use its
9291  * "normal" size request instead of overriding it, i.e.
9292  * you can "unset" the size with -1.
9293  *
9294  * This function sets or unsets both the minimum and natural size.
9295  */
9296 void
9297 clutter_actor_set_size (ClutterActor *self,
9298                         gfloat        width,
9299                         gfloat        height)
9300 {
9301   ClutterSize new_size;
9302
9303   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9304
9305   clutter_size_init (&new_size, width, height);
9306
9307   if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9308     {
9309       /* minor optimization: if we don't have a duration then we can
9310        * skip the get_size() below, to avoid the chance of going through
9311        * get_preferred_width() and get_preferred_height() just to jump to
9312        * a new desired size
9313        */
9314       if (clutter_actor_get_easing_duration (self) == 0)
9315         {
9316           g_object_freeze_notify (G_OBJECT (self));
9317
9318           clutter_actor_set_size_internal (self, &new_size);
9319
9320           g_object_thaw_notify (G_OBJECT (self));
9321
9322           return;
9323         }
9324       else
9325         {
9326           ClutterSize cur_size;
9327
9328           clutter_size_init (&cur_size,
9329                              clutter_actor_get_width (self),
9330                              clutter_actor_get_height (self));
9331
9332          _clutter_actor_create_transition (self,
9333                                            obj_props[PROP_SIZE],
9334                                            &cur_size,
9335                                            &new_size);
9336         }
9337     }
9338   else
9339     _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9340
9341   clutter_actor_queue_relayout (self);
9342 }
9343
9344 /**
9345  * clutter_actor_get_size:
9346  * @self: A #ClutterActor
9347  * @width: (out) (allow-none): return location for the width, or %NULL.
9348  * @height: (out) (allow-none): return location for the height, or %NULL.
9349  *
9350  * This function tries to "do what you mean" and return
9351  * the size an actor will have. If the actor has a valid
9352  * allocation, the allocation will be returned; otherwise,
9353  * the actors natural size request will be returned.
9354  *
9355  * If you care whether you get the request vs. the allocation, you
9356  * should probably call a different function like
9357  * clutter_actor_get_allocation_box() or
9358  * clutter_actor_get_preferred_width().
9359  *
9360  * Since: 0.2
9361  */
9362 void
9363 clutter_actor_get_size (ClutterActor *self,
9364                         gfloat       *width,
9365                         gfloat       *height)
9366 {
9367   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9368
9369   if (width)
9370     *width = clutter_actor_get_width (self);
9371
9372   if (height)
9373     *height = clutter_actor_get_height (self);
9374 }
9375
9376 /**
9377  * clutter_actor_get_position:
9378  * @self: a #ClutterActor
9379  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9380  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9381  *
9382  * This function tries to "do what you mean" and tell you where the
9383  * actor is, prior to any transformations. Retrieves the fixed
9384  * position of an actor in pixels, if one has been set; otherwise, if
9385  * the allocation is valid, returns the actor's allocated position;
9386  * otherwise, returns 0,0.
9387  *
9388  * The returned position is in pixels.
9389  *
9390  * Since: 0.6
9391  */
9392 void
9393 clutter_actor_get_position (ClutterActor *self,
9394                             gfloat       *x,
9395                             gfloat       *y)
9396 {
9397   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9398
9399   if (x)
9400     *x = clutter_actor_get_x (self);
9401
9402   if (y)
9403     *y = clutter_actor_get_y (self);
9404 }
9405
9406 /**
9407  * clutter_actor_get_transformed_position:
9408  * @self: A #ClutterActor
9409  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9410  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9411  *
9412  * Gets the absolute position of an actor, in pixels relative to the stage.
9413  *
9414  * Since: 0.8
9415  */
9416 void
9417 clutter_actor_get_transformed_position (ClutterActor *self,
9418                                         gfloat       *x,
9419                                         gfloat       *y)
9420 {
9421   ClutterVertex v1;
9422   ClutterVertex v2;
9423
9424   v1.x = v1.y = v1.z = 0;
9425   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9426
9427   if (x)
9428     *x = v2.x;
9429
9430   if (y)
9431     *y = v2.y;
9432 }
9433
9434 /**
9435  * clutter_actor_get_transformed_size:
9436  * @self: A #ClutterActor
9437  * @width: (out) (allow-none): return location for the width, or %NULL
9438  * @height: (out) (allow-none): return location for the height, or %NULL
9439  *
9440  * Gets the absolute size of an actor in pixels, taking into account the
9441  * scaling factors.
9442  *
9443  * If the actor has a valid allocation, the allocated size will be used.
9444  * If the actor has not a valid allocation then the preferred size will
9445  * be transformed and returned.
9446  *
9447  * If you want the transformed allocation, see
9448  * clutter_actor_get_abs_allocation_vertices() instead.
9449  *
9450  * <note>When the actor (or one of its ancestors) is rotated around the
9451  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9452  * as a generic quadrangle; in that case this function returns the size
9453  * of the smallest rectangle that encapsulates the entire quad. Please
9454  * note that in this case no assumptions can be made about the relative
9455  * position of this envelope to the absolute position of the actor, as
9456  * returned by clutter_actor_get_transformed_position(); if you need this
9457  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9458  * to get the coords of the actual quadrangle.</note>
9459  *
9460  * Since: 0.8
9461  */
9462 void
9463 clutter_actor_get_transformed_size (ClutterActor *self,
9464                                     gfloat       *width,
9465                                     gfloat       *height)
9466 {
9467   ClutterActorPrivate *priv;
9468   ClutterVertex v[4];
9469   gfloat x_min, x_max, y_min, y_max;
9470   gint i;
9471
9472   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9473
9474   priv = self->priv;
9475
9476   /* if the actor hasn't been allocated yet, get the preferred
9477    * size and transform that
9478    */
9479   if (priv->needs_allocation)
9480     {
9481       gfloat natural_width, natural_height;
9482       ClutterActorBox box;
9483
9484       /* Make a fake allocation to transform.
9485        *
9486        * NB: _clutter_actor_transform_and_project_box expects a box in
9487        * the actor's coordinate space... */
9488
9489       box.x1 = 0;
9490       box.y1 = 0;
9491
9492       natural_width = natural_height = 0;
9493       clutter_actor_get_preferred_size (self, NULL, NULL,
9494                                         &natural_width,
9495                                         &natural_height);
9496
9497       box.x2 = natural_width;
9498       box.y2 = natural_height;
9499
9500       _clutter_actor_transform_and_project_box (self, &box, v);
9501     }
9502   else
9503     clutter_actor_get_abs_allocation_vertices (self, v);
9504
9505   x_min = x_max = v[0].x;
9506   y_min = y_max = v[0].y;
9507
9508   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9509     {
9510       if (v[i].x < x_min)
9511         x_min = v[i].x;
9512
9513       if (v[i].x > x_max)
9514         x_max = v[i].x;
9515
9516       if (v[i].y < y_min)
9517         y_min = v[i].y;
9518
9519       if (v[i].y > y_max)
9520         y_max = v[i].y;
9521     }
9522
9523   if (width)
9524     *width  = x_max - x_min;
9525
9526   if (height)
9527     *height = y_max - y_min;
9528 }
9529
9530 /**
9531  * clutter_actor_get_width:
9532  * @self: A #ClutterActor
9533  *
9534  * Retrieves the width of a #ClutterActor.
9535  *
9536  * If the actor has a valid allocation, this function will return the
9537  * width of the allocated area given to the actor.
9538  *
9539  * If the actor does not have a valid allocation, this function will
9540  * return the actor's natural width, that is the preferred width of
9541  * the actor.
9542  *
9543  * If you care whether you get the preferred width or the width that
9544  * has been assigned to the actor, you should probably call a different
9545  * function like clutter_actor_get_allocation_box() to retrieve the
9546  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9547  * preferred width.
9548  *
9549  * If an actor has a fixed width, for instance a width that has been
9550  * assigned using clutter_actor_set_width(), the width returned will
9551  * be the same value.
9552  *
9553  * Return value: the width of the actor, in pixels
9554  */
9555 gfloat
9556 clutter_actor_get_width (ClutterActor *self)
9557 {
9558   ClutterActorPrivate *priv;
9559
9560   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9561
9562   priv = self->priv;
9563
9564   if (priv->needs_allocation)
9565     {
9566       gfloat natural_width = 0;
9567
9568       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9569         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9570       else
9571         {
9572           gfloat natural_height = 0;
9573
9574           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9575           clutter_actor_get_preferred_width (self, natural_height,
9576                                              NULL,
9577                                              &natural_width);
9578         }
9579
9580       return natural_width;
9581     }
9582   else
9583     return priv->allocation.x2 - priv->allocation.x1;
9584 }
9585
9586 /**
9587  * clutter_actor_get_height:
9588  * @self: A #ClutterActor
9589  *
9590  * Retrieves the height of a #ClutterActor.
9591  *
9592  * If the actor has a valid allocation, this function will return the
9593  * height of the allocated area given to the actor.
9594  *
9595  * If the actor does not have a valid allocation, this function will
9596  * return the actor's natural height, that is the preferred height of
9597  * the actor.
9598  *
9599  * If you care whether you get the preferred height or the height that
9600  * has been assigned to the actor, you should probably call a different
9601  * function like clutter_actor_get_allocation_box() to retrieve the
9602  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9603  * preferred height.
9604  *
9605  * If an actor has a fixed height, for instance a height that has been
9606  * assigned using clutter_actor_set_height(), the height returned will
9607  * be the same value.
9608  *
9609  * Return value: the height of the actor, in pixels
9610  */
9611 gfloat
9612 clutter_actor_get_height (ClutterActor *self)
9613 {
9614   ClutterActorPrivate *priv;
9615
9616   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9617
9618   priv = self->priv;
9619
9620   if (priv->needs_allocation)
9621     {
9622       gfloat natural_height = 0;
9623
9624       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9625         {
9626           gfloat natural_width = 0;
9627
9628           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9629           clutter_actor_get_preferred_height (self, natural_width,
9630                                               NULL, &natural_height);
9631         }
9632       else
9633         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9634
9635       return natural_height;
9636     }
9637   else
9638     return priv->allocation.y2 - priv->allocation.y1;
9639 }
9640
9641 /**
9642  * clutter_actor_set_width:
9643  * @self: A #ClutterActor
9644  * @width: Requested new width for the actor, in pixels, or -1
9645  *
9646  * Forces a width on an actor, causing the actor's preferred width
9647  * and height (if any) to be ignored.
9648  *
9649  * If @width is -1 the actor will use its preferred width request
9650  * instead of overriding it, i.e. you can "unset" the width with -1.
9651  *
9652  * This function sets both the minimum and natural size of the actor.
9653  *
9654  * since: 0.2
9655  */
9656 void
9657 clutter_actor_set_width (ClutterActor *self,
9658                          gfloat        width)
9659 {
9660   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9661
9662   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9663     {
9664       float cur_size;
9665
9666       /* minor optimization: if we don't have a duration
9667        * then we can skip the get_width() below, to avoid
9668        * the chance of going through get_preferred_width()
9669        * just to jump to a new desired width.
9670        */
9671       if (clutter_actor_get_easing_duration (self) == 0)
9672         {
9673           g_object_freeze_notify (G_OBJECT (self));
9674
9675           clutter_actor_set_width_internal (self, width);
9676
9677           g_object_thaw_notify (G_OBJECT (self));
9678
9679           return;
9680         }
9681       else
9682         cur_size = clutter_actor_get_width (self);
9683
9684       _clutter_actor_create_transition (self,
9685                                         obj_props[PROP_WIDTH],
9686                                         cur_size,
9687                                         width);
9688     }
9689   else
9690     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9691 }
9692
9693 /**
9694  * clutter_actor_set_height:
9695  * @self: A #ClutterActor
9696  * @height: Requested new height for the actor, in pixels, or -1
9697  *
9698  * Forces a height on an actor, causing the actor's preferred width
9699  * and height (if any) to be ignored.
9700  *
9701  * If @height is -1 the actor will use its preferred height instead of
9702  * overriding it, i.e. you can "unset" the height with -1.
9703  *
9704  * This function sets both the minimum and natural size of the actor.
9705  *
9706  * since: 0.2
9707  */
9708 void
9709 clutter_actor_set_height (ClutterActor *self,
9710                           gfloat        height)
9711 {
9712   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9713
9714   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9715     {
9716       float cur_size;
9717
9718       /* see the comment in clutter_actor_set_width() above */
9719       if (clutter_actor_get_easing_duration (self) == 0)
9720         {
9721           g_object_freeze_notify (G_OBJECT (self));
9722
9723           clutter_actor_set_height_internal (self, height);
9724
9725           g_object_thaw_notify (G_OBJECT (self));
9726
9727           return;
9728         }
9729       else
9730         cur_size = clutter_actor_get_height (self);
9731
9732       _clutter_actor_create_transition (self,
9733                                         obj_props[PROP_HEIGHT],
9734                                         cur_size,
9735                                         height);
9736     }
9737   else
9738     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9739 }
9740
9741 static inline void
9742 clutter_actor_set_x_internal (ClutterActor *self,
9743                               float         x)
9744 {
9745   ClutterActorPrivate *priv = self->priv;
9746   ClutterLayoutInfo *linfo;
9747   ClutterActorBox old = { 0, };
9748
9749   linfo = _clutter_actor_get_layout_info (self);
9750
9751   if (priv->position_set && linfo->fixed_pos.x == x)
9752     return;
9753
9754   clutter_actor_store_old_geometry (self, &old);
9755
9756   linfo->fixed_pos.x = x;
9757   clutter_actor_set_fixed_position_set (self, TRUE);
9758
9759   clutter_actor_notify_if_geometry_changed (self, &old);
9760
9761   clutter_actor_queue_relayout (self);
9762 }
9763
9764 static inline void
9765 clutter_actor_set_y_internal (ClutterActor *self,
9766                               float         y)
9767 {
9768   ClutterActorPrivate *priv = self->priv;
9769   ClutterLayoutInfo *linfo;
9770   ClutterActorBox old = { 0, };
9771
9772   linfo = _clutter_actor_get_layout_info (self);
9773
9774   if (priv->position_set && linfo->fixed_pos.y == y)
9775     return;
9776
9777   clutter_actor_store_old_geometry (self, &old);
9778
9779   linfo->fixed_pos.y = y;
9780   clutter_actor_set_fixed_position_set (self, TRUE);
9781
9782   clutter_actor_notify_if_geometry_changed (self, &old);
9783
9784   clutter_actor_queue_relayout (self);
9785 }
9786
9787 static void
9788 clutter_actor_set_position_internal (ClutterActor       *self,
9789                                      const ClutterPoint *position)
9790 {
9791   ClutterActorPrivate *priv = self->priv;
9792   ClutterLayoutInfo *linfo;
9793   ClutterActorBox old = { 0, };
9794
9795   linfo = _clutter_actor_get_layout_info (self);
9796
9797   if (priv->position_set &&
9798       clutter_point_equals (position, &linfo->fixed_pos))
9799     return;
9800
9801   clutter_actor_store_old_geometry (self, &old);
9802
9803   if (position != NULL)
9804     {
9805       linfo->fixed_pos = *position;
9806       clutter_actor_set_fixed_position_set (self, TRUE);
9807     }
9808   else
9809     clutter_actor_set_fixed_position_set (self, FALSE);
9810
9811   clutter_actor_notify_if_geometry_changed (self, &old);
9812
9813   clutter_actor_queue_relayout (self);
9814 }
9815
9816 /**
9817  * clutter_actor_set_x:
9818  * @self: a #ClutterActor
9819  * @x: the actor's position on the X axis
9820  *
9821  * Sets the actor's X coordinate, relative to its parent, in pixels.
9822  *
9823  * Overrides any layout manager and forces a fixed position for
9824  * the actor.
9825  *
9826  * The #ClutterActor:x property is animatable.
9827  *
9828  * Since: 0.6
9829  */
9830 void
9831 clutter_actor_set_x (ClutterActor *self,
9832                      gfloat        x)
9833 {
9834   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9835
9836   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9837     {
9838       float cur_position = clutter_actor_get_x (self);
9839
9840       _clutter_actor_create_transition (self, obj_props[PROP_X],
9841                                         cur_position,
9842                                         x);
9843     }
9844   else
9845     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9846 }
9847
9848 /**
9849  * clutter_actor_set_y:
9850  * @self: a #ClutterActor
9851  * @y: the actor's position on the Y axis
9852  *
9853  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9854  *
9855  * Overrides any layout manager and forces a fixed position for
9856  * the actor.
9857  *
9858  * The #ClutterActor:y property is animatable.
9859  *
9860  * Since: 0.6
9861  */
9862 void
9863 clutter_actor_set_y (ClutterActor *self,
9864                      gfloat        y)
9865 {
9866   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9867
9868   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9869     {
9870       float cur_position = clutter_actor_get_y (self);
9871
9872       _clutter_actor_create_transition (self, obj_props[PROP_Y],
9873                                         cur_position,
9874                                         y);
9875     }
9876   else
9877     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9878 }
9879
9880 /**
9881  * clutter_actor_get_x:
9882  * @self: A #ClutterActor
9883  *
9884  * Retrieves the X coordinate of a #ClutterActor.
9885  *
9886  * This function tries to "do what you mean", by returning the
9887  * correct value depending on the actor's state.
9888  *
9889  * If the actor has a valid allocation, this function will return
9890  * the X coordinate of the origin of the allocation box.
9891  *
9892  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9893  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9894  * function will return that coordinate.
9895  *
9896  * If both the allocation and a fixed position are missing, this function
9897  * will return 0.
9898  *
9899  * Return value: the X coordinate, in pixels, ignoring any
9900  *   transformation (i.e. scaling, rotation)
9901  */
9902 gfloat
9903 clutter_actor_get_x (ClutterActor *self)
9904 {
9905   ClutterActorPrivate *priv;
9906
9907   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9908
9909   priv = self->priv;
9910
9911   if (priv->needs_allocation)
9912     {
9913       if (priv->position_set)
9914         {
9915           const ClutterLayoutInfo *info;
9916
9917           info = _clutter_actor_get_layout_info_or_defaults (self);
9918
9919           return info->fixed_pos.x;
9920         }
9921       else
9922         return 0;
9923     }
9924   else
9925     return priv->allocation.x1;
9926 }
9927
9928 /**
9929  * clutter_actor_get_y:
9930  * @self: A #ClutterActor
9931  *
9932  * Retrieves the Y coordinate of a #ClutterActor.
9933  *
9934  * This function tries to "do what you mean", by returning the
9935  * correct value depending on the actor's state.
9936  *
9937  * If the actor has a valid allocation, this function will return
9938  * the Y coordinate of the origin of the allocation box.
9939  *
9940  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9941  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9942  * function will return that coordinate.
9943  *
9944  * If both the allocation and a fixed position are missing, this function
9945  * will return 0.
9946  *
9947  * Return value: the Y coordinate, in pixels, ignoring any
9948  *   transformation (i.e. scaling, rotation)
9949  */
9950 gfloat
9951 clutter_actor_get_y (ClutterActor *self)
9952 {
9953   ClutterActorPrivate *priv;
9954
9955   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9956
9957   priv = self->priv;
9958
9959   if (priv->needs_allocation)
9960     {
9961       if (priv->position_set)
9962         {
9963           const ClutterLayoutInfo *info;
9964
9965           info = _clutter_actor_get_layout_info_or_defaults (self);
9966
9967           return info->fixed_pos.y;
9968         }
9969       else
9970         return 0;
9971     }
9972   else
9973     return priv->allocation.y1;
9974 }
9975
9976 /**
9977  * clutter_actor_set_scale:
9978  * @self: A #ClutterActor
9979  * @scale_x: double factor to scale actor by horizontally.
9980  * @scale_y: double factor to scale actor by vertically.
9981  *
9982  * Scales an actor with the given factors. The scaling is relative to
9983  * the scale center and the anchor point. The scale center is
9984  * unchanged by this function and defaults to 0,0.
9985  *
9986  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9987  * animatable.
9988  *
9989  * Since: 0.2
9990  */
9991 void
9992 clutter_actor_set_scale (ClutterActor *self,
9993                          gdouble       scale_x,
9994                          gdouble       scale_y)
9995 {
9996   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9997
9998   g_object_freeze_notify (G_OBJECT (self));
9999
10000   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10001   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10002
10003   g_object_thaw_notify (G_OBJECT (self));
10004 }
10005
10006 /**
10007  * clutter_actor_set_scale_full:
10008  * @self: A #ClutterActor
10009  * @scale_x: double factor to scale actor by horizontally.
10010  * @scale_y: double factor to scale actor by vertically.
10011  * @center_x: X coordinate of the center of the scale.
10012  * @center_y: Y coordinate of the center of the scale
10013  *
10014  * Scales an actor with the given factors around the given center
10015  * point. The center point is specified in pixels relative to the
10016  * anchor point (usually the top left corner of the actor).
10017  *
10018  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10019  * are animatable.
10020  *
10021  * Since: 1.0
10022  */
10023 void
10024 clutter_actor_set_scale_full (ClutterActor *self,
10025                               gdouble       scale_x,
10026                               gdouble       scale_y,
10027                               gfloat        center_x,
10028                               gfloat        center_y)
10029 {
10030   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10031
10032   g_object_freeze_notify (G_OBJECT (self));
10033
10034   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10035   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10036   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10037   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10038
10039   g_object_thaw_notify (G_OBJECT (self));
10040 }
10041
10042 /**
10043  * clutter_actor_set_scale_with_gravity:
10044  * @self: A #ClutterActor
10045  * @scale_x: double factor to scale actor by horizontally.
10046  * @scale_y: double factor to scale actor by vertically.
10047  * @gravity: the location of the scale center expressed as a compass
10048  * direction.
10049  *
10050  * Scales an actor with the given factors around the given
10051  * center point. The center point is specified as one of the compass
10052  * directions in #ClutterGravity. For example, setting it to north
10053  * will cause the top of the actor to remain unchanged and the rest of
10054  * the actor to expand left, right and downwards.
10055  *
10056  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10057  * animatable.
10058  *
10059  * Since: 1.0
10060  */
10061 void
10062 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
10063                                       gdouble         scale_x,
10064                                       gdouble         scale_y,
10065                                       ClutterGravity  gravity)
10066 {
10067   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10068
10069   g_object_freeze_notify (G_OBJECT (self));
10070
10071   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10072   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10073   clutter_actor_set_scale_gravity (self, gravity);
10074
10075   g_object_thaw_notify (G_OBJECT (self));
10076 }
10077
10078 /**
10079  * clutter_actor_get_scale:
10080  * @self: A #ClutterActor
10081  * @scale_x: (out) (allow-none): Location to store horizonal
10082  *   scale factor, or %NULL.
10083  * @scale_y: (out) (allow-none): Location to store vertical
10084  *   scale factor, or %NULL.
10085  *
10086  * Retrieves an actors scale factors.
10087  *
10088  * Since: 0.2
10089  */
10090 void
10091 clutter_actor_get_scale (ClutterActor *self,
10092                          gdouble      *scale_x,
10093                          gdouble      *scale_y)
10094 {
10095   const ClutterTransformInfo *info;
10096
10097   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10098
10099   info = _clutter_actor_get_transform_info_or_defaults (self);
10100
10101   if (scale_x)
10102     *scale_x = info->scale_x;
10103
10104   if (scale_y)
10105     *scale_y = info->scale_y;
10106 }
10107
10108 /**
10109  * clutter_actor_get_scale_center:
10110  * @self: A #ClutterActor
10111  * @center_x: (out) (allow-none): Location to store the X position
10112  *   of the scale center, or %NULL.
10113  * @center_y: (out) (allow-none): Location to store the Y position
10114  *   of the scale center, or %NULL.
10115  *
10116  * Retrieves the scale center coordinate in pixels relative to the top
10117  * left corner of the actor. If the scale center was specified using a
10118  * #ClutterGravity this will calculate the pixel offset using the
10119  * current size of the actor.
10120  *
10121  * Since: 1.0
10122  */
10123 void
10124 clutter_actor_get_scale_center (ClutterActor *self,
10125                                 gfloat       *center_x,
10126                                 gfloat       *center_y)
10127 {
10128   const ClutterTransformInfo *info;
10129
10130   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10131
10132   info = _clutter_actor_get_transform_info_or_defaults (self);
10133
10134   clutter_anchor_coord_get_units (self, &info->scale_center,
10135                                   center_x,
10136                                   center_y,
10137                                   NULL);
10138 }
10139
10140 /**
10141  * clutter_actor_get_scale_gravity:
10142  * @self: A #ClutterActor
10143  *
10144  * Retrieves the scale center as a compass direction. If the scale
10145  * center was specified in pixels or units this will return
10146  * %CLUTTER_GRAVITY_NONE.
10147  *
10148  * Return value: the scale gravity
10149  *
10150  * Since: 1.0
10151  */
10152 ClutterGravity
10153 clutter_actor_get_scale_gravity (ClutterActor *self)
10154 {
10155   const ClutterTransformInfo *info;
10156
10157   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10158
10159   info = _clutter_actor_get_transform_info_or_defaults (self);
10160
10161   return clutter_anchor_coord_get_gravity (&info->scale_center);
10162 }
10163
10164 static inline void
10165 clutter_actor_set_opacity_internal (ClutterActor *self,
10166                                     guint8        opacity)
10167 {
10168   ClutterActorPrivate *priv = self->priv;
10169
10170   if (priv->opacity != opacity)
10171     {
10172       priv->opacity = opacity;
10173
10174       /* Queue a redraw from the flatten effect so that it can use
10175          its cached image if available instead of having to redraw the
10176          actual actor. If it doesn't end up using the FBO then the
10177          effect is still able to continue the paint anyway. If there
10178          is no flatten effect yet then this is equivalent to queueing
10179          a full redraw */
10180       _clutter_actor_queue_redraw_full (self,
10181                                         0, /* flags */
10182                                         NULL, /* clip */
10183                                         priv->flatten_effect);
10184
10185       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10186     }
10187 }
10188
10189 /**
10190  * clutter_actor_set_opacity:
10191  * @self: A #ClutterActor
10192  * @opacity: New opacity value for the actor.
10193  *
10194  * Sets the actor's opacity, with zero being completely transparent and
10195  * 255 (0xff) being fully opaque.
10196  *
10197  * The #ClutterActor:opacity property is animatable.
10198  */
10199 void
10200 clutter_actor_set_opacity (ClutterActor *self,
10201                            guint8        opacity)
10202 {
10203   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10204
10205   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10206     {
10207       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10208                                         self->priv->opacity,
10209                                         opacity);
10210     }
10211   else
10212     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10213 }
10214
10215 /*
10216  * clutter_actor_get_paint_opacity_internal:
10217  * @self: a #ClutterActor
10218  *
10219  * Retrieves the absolute opacity of the actor, as it appears on the stage
10220  *
10221  * This function does not do type checks
10222  *
10223  * Return value: the absolute opacity of the actor
10224  */
10225 static guint8
10226 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10227 {
10228   ClutterActorPrivate *priv = self->priv;
10229   ClutterActor *parent;
10230
10231   /* override the top-level opacity to always be 255; even in
10232    * case of ClutterStage:use-alpha being TRUE we want the rest
10233    * of the scene to be painted
10234    */
10235   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10236     return 255;
10237
10238   if (priv->opacity_override >= 0)
10239     return priv->opacity_override;
10240
10241   parent = priv->parent;
10242
10243   /* Factor in the actual actors opacity with parents */
10244   if (parent != NULL)
10245     {
10246       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10247
10248       if (opacity != 0xff)
10249         return (opacity * priv->opacity) / 0xff;
10250     }
10251
10252   return priv->opacity;
10253
10254 }
10255
10256 /**
10257  * clutter_actor_get_paint_opacity:
10258  * @self: A #ClutterActor
10259  *
10260  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10261  *
10262  * This function traverses the hierarchy chain and composites the opacity of
10263  * the actor with that of its parents.
10264  *
10265  * This function is intended for subclasses to use in the paint virtual
10266  * function, to paint themselves with the correct opacity.
10267  *
10268  * Return value: The actor opacity value.
10269  *
10270  * Since: 0.8
10271  */
10272 guint8
10273 clutter_actor_get_paint_opacity (ClutterActor *self)
10274 {
10275   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10276
10277   return clutter_actor_get_paint_opacity_internal (self);
10278 }
10279
10280 /**
10281  * clutter_actor_get_opacity:
10282  * @self: a #ClutterActor
10283  *
10284  * Retrieves the opacity value of an actor, as set by
10285  * clutter_actor_set_opacity().
10286  *
10287  * For retrieving the absolute opacity of the actor inside a paint
10288  * virtual function, see clutter_actor_get_paint_opacity().
10289  *
10290  * Return value: the opacity of the actor
10291  */
10292 guint8
10293 clutter_actor_get_opacity (ClutterActor *self)
10294 {
10295   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10296
10297   return self->priv->opacity;
10298 }
10299
10300 /**
10301  * clutter_actor_set_offscreen_redirect:
10302  * @self: A #ClutterActor
10303  * @redirect: New offscreen redirect flags for the actor.
10304  *
10305  * Defines the circumstances where the actor should be redirected into
10306  * an offscreen image. The offscreen image is used to flatten the
10307  * actor into a single image while painting for two main reasons.
10308  * Firstly, when the actor is painted a second time without any of its
10309  * contents changing it can simply repaint the cached image without
10310  * descending further down the actor hierarchy. Secondly, it will make
10311  * the opacity look correct even if there are overlapping primitives
10312  * in the actor.
10313  *
10314  * Caching the actor could in some cases be a performance win and in
10315  * some cases be a performance lose so it is important to determine
10316  * which value is right for an actor before modifying this value. For
10317  * example, there is never any reason to flatten an actor that is just
10318  * a single texture (such as a #ClutterTexture) because it is
10319  * effectively already cached in an image so the offscreen would be
10320  * redundant. Also if the actor contains primitives that are far apart
10321  * with a large transparent area in the middle (such as a large
10322  * CluterGroup with a small actor in the top left and a small actor in
10323  * the bottom right) then the cached image will contain the entire
10324  * image of the large area and the paint will waste time blending all
10325  * of the transparent pixels in the middle.
10326  *
10327  * The default method of implementing opacity on a container simply
10328  * forwards on the opacity to all of the children. If the children are
10329  * overlapping then it will appear as if they are two separate glassy
10330  * objects and there will be a break in the color where they
10331  * overlap. By redirecting to an offscreen buffer it will be as if the
10332  * two opaque objects are combined into one and then made transparent
10333  * which is usually what is expected.
10334  *
10335  * The image below demonstrates the difference between redirecting and
10336  * not. The image shows two Clutter groups, each containing a red and
10337  * a green rectangle which overlap. The opacity on the group is set to
10338  * 128 (which is 50%). When the offscreen redirect is not used, the
10339  * red rectangle can be seen through the blue rectangle as if the two
10340  * rectangles were separately transparent. When the redirect is used
10341  * the group as a whole is transparent instead so the red rectangle is
10342  * not visible where they overlap.
10343  *
10344  * <figure id="offscreen-redirect">
10345  *   <title>Sample of using an offscreen redirect for transparency</title>
10346  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10347  * </figure>
10348  *
10349  * The default value for this property is 0, so we effectively will
10350  * never redirect an actor offscreen by default. This means that there
10351  * are times that transparent actors may look glassy as described
10352  * above. The reason this is the default is because there is a
10353  * performance trade off between quality and performance here. In many
10354  * cases the default form of glassy opacity looks good enough, but if
10355  * it's not you will need to set the
10356  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10357  * redirection for opacity.
10358  *
10359  * Custom actors that don't contain any overlapping primitives are
10360  * recommended to override the has_overlaps() virtual to return %FALSE
10361  * for maximum efficiency.
10362  *
10363  * Since: 1.8
10364  */
10365 void
10366 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10367                                       ClutterOffscreenRedirect redirect)
10368 {
10369   ClutterActorPrivate *priv;
10370
10371   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10372
10373   priv = self->priv;
10374
10375   if (priv->offscreen_redirect != redirect)
10376     {
10377       priv->offscreen_redirect = redirect;
10378
10379       /* Queue a redraw from the effect so that it can use its cached
10380          image if available instead of having to redraw the actual
10381          actor. If it doesn't end up using the FBO then the effect is
10382          still able to continue the paint anyway. If there is no
10383          effect then this is equivalent to queuing a full redraw */
10384       _clutter_actor_queue_redraw_full (self,
10385                                         0, /* flags */
10386                                         NULL, /* clip */
10387                                         priv->flatten_effect);
10388
10389       g_object_notify_by_pspec (G_OBJECT (self),
10390                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10391     }
10392 }
10393
10394 /**
10395  * clutter_actor_get_offscreen_redirect:
10396  * @self: a #ClutterActor
10397  *
10398  * Retrieves whether to redirect the actor to an offscreen buffer, as
10399  * set by clutter_actor_set_offscreen_redirect().
10400  *
10401  * Return value: the value of the offscreen-redirect property of the actor
10402  *
10403  * Since: 1.8
10404  */
10405 ClutterOffscreenRedirect
10406 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10407 {
10408   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10409
10410   return self->priv->offscreen_redirect;
10411 }
10412
10413 /**
10414  * clutter_actor_set_name:
10415  * @self: A #ClutterActor
10416  * @name: Textual tag to apply to actor
10417  *
10418  * Sets the given name to @self. The name can be used to identify
10419  * a #ClutterActor.
10420  */
10421 void
10422 clutter_actor_set_name (ClutterActor *self,
10423                         const gchar  *name)
10424 {
10425   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10426
10427   g_free (self->priv->name);
10428   self->priv->name = g_strdup (name);
10429
10430   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10431 }
10432
10433 /**
10434  * clutter_actor_get_name:
10435  * @self: A #ClutterActor
10436  *
10437  * Retrieves the name of @self.
10438  *
10439  * Return value: the name of the actor, or %NULL. The returned string is
10440  *   owned by the actor and should not be modified or freed.
10441  */
10442 const gchar *
10443 clutter_actor_get_name (ClutterActor *self)
10444 {
10445   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10446
10447   return self->priv->name;
10448 }
10449
10450 /**
10451  * clutter_actor_get_gid:
10452  * @self: A #ClutterActor
10453  *
10454  * Retrieves the unique id for @self.
10455  *
10456  * Return value: Globally unique value for this object instance.
10457  *
10458  * Since: 0.6
10459  *
10460  * Deprecated: 1.8: The id is not used any longer.
10461  */
10462 guint32
10463 clutter_actor_get_gid (ClutterActor *self)
10464 {
10465   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10466
10467   return self->priv->id;
10468 }
10469
10470 static inline void
10471 clutter_actor_set_depth_internal (ClutterActor *self,
10472                                   float         depth)
10473 {
10474   ClutterTransformInfo *info;
10475
10476   info = _clutter_actor_get_transform_info (self);
10477
10478   if (info->depth != depth)
10479     {
10480       /* Sets Z value - XXX 2.0: should we invert? */
10481       info->depth = depth;
10482
10483       self->priv->transform_valid = FALSE;
10484
10485       /* FIXME - remove this crap; sadly, there are still containers
10486        * in Clutter that depend on this utter brain damage
10487        */
10488       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10489
10490       clutter_actor_queue_redraw (self);
10491
10492       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10493     }
10494 }
10495
10496 /**
10497  * clutter_actor_set_depth:
10498  * @self: a #ClutterActor
10499  * @depth: Z co-ord
10500  *
10501  * Sets the Z coordinate of @self to @depth.
10502  *
10503  * The unit used by @depth is dependant on the perspective setup. See
10504  * also clutter_stage_set_perspective().
10505  */
10506 void
10507 clutter_actor_set_depth (ClutterActor *self,
10508                          gfloat        depth)
10509 {
10510   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10511
10512   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10513     {
10514       const ClutterTransformInfo *info;
10515
10516       info = _clutter_actor_get_transform_info_or_defaults (self);
10517
10518       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10519                                         info->depth,
10520                                         depth);
10521     }
10522   else
10523     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10524
10525   clutter_actor_queue_redraw (self);
10526 }
10527
10528 /**
10529  * clutter_actor_get_depth:
10530  * @self: a #ClutterActor
10531  *
10532  * Retrieves the depth of @self.
10533  *
10534  * Return value: the depth of the actor
10535  */
10536 gfloat
10537 clutter_actor_get_depth (ClutterActor *self)
10538 {
10539   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10540
10541   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10542 }
10543
10544 /**
10545  * clutter_actor_set_rotation:
10546  * @self: a #ClutterActor
10547  * @axis: the axis of rotation
10548  * @angle: the angle of rotation
10549  * @x: X coordinate of the rotation center
10550  * @y: Y coordinate of the rotation center
10551  * @z: Z coordinate of the rotation center
10552  *
10553  * Sets the rotation angle of @self around the given axis.
10554  *
10555  * The rotation center coordinates used depend on the value of @axis:
10556  * <itemizedlist>
10557  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10558  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10559  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10560  * </itemizedlist>
10561  *
10562  * The rotation coordinates are relative to the anchor point of the
10563  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10564  * point is set, the upper left corner is assumed as the origin.
10565  *
10566  * Since: 0.8
10567  */
10568 void
10569 clutter_actor_set_rotation (ClutterActor      *self,
10570                             ClutterRotateAxis  axis,
10571                             gdouble            angle,
10572                             gfloat             x,
10573                             gfloat             y,
10574                             gfloat             z)
10575 {
10576   ClutterVertex v;
10577
10578   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10579
10580   v.x = x;
10581   v.y = y;
10582   v.z = z;
10583
10584   g_object_freeze_notify (G_OBJECT (self));
10585
10586   clutter_actor_set_rotation_angle (self, axis, angle);
10587   clutter_actor_set_rotation_center_internal (self, axis, &v);
10588
10589   g_object_thaw_notify (G_OBJECT (self));
10590 }
10591
10592 /**
10593  * clutter_actor_set_z_rotation_from_gravity:
10594  * @self: a #ClutterActor
10595  * @angle: the angle of rotation
10596  * @gravity: the center point of the rotation
10597  *
10598  * Sets the rotation angle of @self around the Z axis using the center
10599  * point specified as a compass point. For example to rotate such that
10600  * the center of the actor remains static you can use
10601  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10602  * will move accordingly.
10603  *
10604  * Since: 1.0
10605  */
10606 void
10607 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10608                                            gdouble         angle,
10609                                            ClutterGravity  gravity)
10610 {
10611   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10612
10613   if (gravity == CLUTTER_GRAVITY_NONE)
10614     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10615   else
10616     {
10617       GObject *obj = G_OBJECT (self);
10618       ClutterTransformInfo *info;
10619
10620       info = _clutter_actor_get_transform_info (self);
10621
10622       g_object_freeze_notify (obj);
10623
10624       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10625
10626       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10627       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10628       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10629
10630       g_object_thaw_notify (obj);
10631     }
10632 }
10633
10634 /**
10635  * clutter_actor_get_rotation:
10636  * @self: a #ClutterActor
10637  * @axis: the axis of rotation
10638  * @x: (out): return value for the X coordinate of the center of rotation
10639  * @y: (out): return value for the Y coordinate of the center of rotation
10640  * @z: (out): return value for the Z coordinate of the center of rotation
10641  *
10642  * Retrieves the angle and center of rotation on the given axis,
10643  * set using clutter_actor_set_rotation().
10644  *
10645  * Return value: the angle of rotation
10646  *
10647  * Since: 0.8
10648  */
10649 gdouble
10650 clutter_actor_get_rotation (ClutterActor      *self,
10651                             ClutterRotateAxis  axis,
10652                             gfloat            *x,
10653                             gfloat            *y,
10654                             gfloat            *z)
10655 {
10656   const ClutterTransformInfo *info;
10657   const AnchorCoord *anchor_coord;
10658   gdouble retval = 0;
10659
10660   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10661
10662   info = _clutter_actor_get_transform_info_or_defaults (self);
10663
10664   switch (axis)
10665     {
10666     case CLUTTER_X_AXIS:
10667       anchor_coord = &info->rx_center;
10668       retval = info->rx_angle;
10669       break;
10670
10671     case CLUTTER_Y_AXIS:
10672       anchor_coord = &info->ry_center;
10673       retval = info->ry_angle;
10674       break;
10675
10676     case CLUTTER_Z_AXIS:
10677       anchor_coord = &info->rz_center;
10678       retval = info->rz_angle;
10679       break;
10680
10681     default:
10682       anchor_coord = NULL;
10683       retval = 0.0;
10684       break;
10685     }
10686
10687   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10688
10689   return retval;
10690 }
10691
10692 /**
10693  * clutter_actor_get_z_rotation_gravity:
10694  * @self: A #ClutterActor
10695  *
10696  * Retrieves the center for the rotation around the Z axis as a
10697  * compass direction. If the center was specified in pixels or units
10698  * this will return %CLUTTER_GRAVITY_NONE.
10699  *
10700  * Return value: the Z rotation center
10701  *
10702  * Since: 1.0
10703  */
10704 ClutterGravity
10705 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10706 {
10707   const ClutterTransformInfo *info;
10708
10709   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10710
10711   info = _clutter_actor_get_transform_info_or_defaults (self);
10712
10713   return clutter_anchor_coord_get_gravity (&info->rz_center);
10714 }
10715
10716 /**
10717  * clutter_actor_set_clip:
10718  * @self: A #ClutterActor
10719  * @xoff: X offset of the clip rectangle
10720  * @yoff: Y offset of the clip rectangle
10721  * @width: Width of the clip rectangle
10722  * @height: Height of the clip rectangle
10723  *
10724  * Sets clip area for @self. The clip area is always computed from the
10725  * upper left corner of the actor, even if the anchor point is set
10726  * otherwise.
10727  *
10728  * Since: 0.6
10729  */
10730 void
10731 clutter_actor_set_clip (ClutterActor *self,
10732                         gfloat        xoff,
10733                         gfloat        yoff,
10734                         gfloat        width,
10735                         gfloat        height)
10736 {
10737   ClutterActorPrivate *priv;
10738
10739   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10740
10741   priv = self->priv;
10742
10743   if (priv->has_clip &&
10744       priv->clip.x == xoff &&
10745       priv->clip.y == yoff &&
10746       priv->clip.width == width &&
10747       priv->clip.height == height)
10748     return;
10749
10750   priv->clip.x = xoff;
10751   priv->clip.y = yoff;
10752   priv->clip.width = width;
10753   priv->clip.height = height;
10754
10755   priv->has_clip = TRUE;
10756
10757   clutter_actor_queue_redraw (self);
10758
10759   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10760   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10761 }
10762
10763 /**
10764  * clutter_actor_remove_clip:
10765  * @self: A #ClutterActor
10766  *
10767  * Removes clip area from @self.
10768  */
10769 void
10770 clutter_actor_remove_clip (ClutterActor *self)
10771 {
10772   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10773
10774   if (!self->priv->has_clip)
10775     return;
10776
10777   self->priv->has_clip = FALSE;
10778
10779   clutter_actor_queue_redraw (self);
10780
10781   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10782 }
10783
10784 /**
10785  * clutter_actor_has_clip:
10786  * @self: a #ClutterActor
10787  *
10788  * Determines whether the actor has a clip area set or not.
10789  *
10790  * Return value: %TRUE if the actor has a clip area set.
10791  *
10792  * Since: 0.1.1
10793  */
10794 gboolean
10795 clutter_actor_has_clip (ClutterActor *self)
10796 {
10797   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10798
10799   return self->priv->has_clip;
10800 }
10801
10802 /**
10803  * clutter_actor_get_clip:
10804  * @self: a #ClutterActor
10805  * @xoff: (out) (allow-none): return location for the X offset of
10806  *   the clip rectangle, or %NULL
10807  * @yoff: (out) (allow-none): return location for the Y offset of
10808  *   the clip rectangle, or %NULL
10809  * @width: (out) (allow-none): return location for the width of
10810  *   the clip rectangle, or %NULL
10811  * @height: (out) (allow-none): return location for the height of
10812  *   the clip rectangle, or %NULL
10813  *
10814  * Gets the clip area for @self, if any is set
10815  *
10816  * Since: 0.6
10817  */
10818 void
10819 clutter_actor_get_clip (ClutterActor *self,
10820                         gfloat       *xoff,
10821                         gfloat       *yoff,
10822                         gfloat       *width,
10823                         gfloat       *height)
10824 {
10825   ClutterActorPrivate *priv;
10826
10827   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10828
10829   priv = self->priv;
10830
10831   if (!priv->has_clip)
10832     return;
10833
10834   if (xoff != NULL)
10835     *xoff = priv->clip.x;
10836
10837   if (yoff != NULL)
10838     *yoff = priv->clip.y;
10839
10840   if (width != NULL)
10841     *width = priv->clip.width;
10842
10843   if (height != NULL)
10844     *height = priv->clip.height;
10845 }
10846
10847 /**
10848  * clutter_actor_get_children:
10849  * @self: a #ClutterActor
10850  *
10851  * Retrieves the list of children of @self.
10852  *
10853  * Return value: (transfer container) (element-type ClutterActor): A newly
10854  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10855  *   done.
10856  *
10857  * Since: 1.10
10858  */
10859 GList *
10860 clutter_actor_get_children (ClutterActor *self)
10861 {
10862   ClutterActor *iter;
10863   GList *res;
10864
10865   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10866
10867   /* we walk the list backward so that we can use prepend(),
10868    * which is O(1)
10869    */
10870   for (iter = self->priv->last_child, res = NULL;
10871        iter != NULL;
10872        iter = iter->priv->prev_sibling)
10873     {
10874       res = g_list_prepend (res, iter);
10875     }
10876
10877   return res;
10878 }
10879
10880 /*< private >
10881  * insert_child_at_depth:
10882  * @self: a #ClutterActor
10883  * @child: a #ClutterActor
10884  *
10885  * Inserts @child inside the list of children held by @self, using
10886  * the depth as the insertion criteria.
10887  *
10888  * This sadly makes the insertion not O(1), but we can keep the
10889  * list sorted so that the painters algorithm we use for painting
10890  * the children will work correctly.
10891  */
10892 static void
10893 insert_child_at_depth (ClutterActor *self,
10894                        ClutterActor *child,
10895                        gpointer      dummy G_GNUC_UNUSED)
10896 {
10897   ClutterActor *iter;
10898   float child_depth;
10899
10900   child->priv->parent = self;
10901
10902   child_depth =
10903     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10904
10905   /* special-case the first child */
10906   if (self->priv->n_children == 0)
10907     {
10908       self->priv->first_child = child;
10909       self->priv->last_child = child;
10910
10911       child->priv->next_sibling = NULL;
10912       child->priv->prev_sibling = NULL;
10913
10914       return;
10915     }
10916
10917   /* Find the right place to insert the child so that it will still be
10918      sorted and the child will be after all of the actors at the same
10919      dept */
10920   for (iter = self->priv->first_child;
10921        iter != NULL;
10922        iter = iter->priv->next_sibling)
10923     {
10924       float iter_depth;
10925
10926       iter_depth =
10927         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10928
10929       if (iter_depth > child_depth)
10930         break;
10931     }
10932
10933   if (iter != NULL)
10934     {
10935       ClutterActor *tmp = iter->priv->prev_sibling;
10936
10937       if (tmp != NULL)
10938         tmp->priv->next_sibling = child;
10939
10940       /* Insert the node before the found one */
10941       child->priv->prev_sibling = iter->priv->prev_sibling;
10942       child->priv->next_sibling = iter;
10943       iter->priv->prev_sibling = child;
10944     }
10945   else
10946     {
10947       ClutterActor *tmp = self->priv->last_child;
10948
10949       if (tmp != NULL)
10950         tmp->priv->next_sibling = child;
10951
10952       /* insert the node at the end of the list */
10953       child->priv->prev_sibling = self->priv->last_child;
10954       child->priv->next_sibling = NULL;
10955     }
10956
10957   if (child->priv->prev_sibling == NULL)
10958     self->priv->first_child = child;
10959
10960   if (child->priv->next_sibling == NULL)
10961     self->priv->last_child = child;
10962 }
10963
10964 static void
10965 insert_child_at_index (ClutterActor *self,
10966                        ClutterActor *child,
10967                        gpointer      data_)
10968 {
10969   gint index_ = GPOINTER_TO_INT (data_);
10970
10971   child->priv->parent = self;
10972
10973   if (index_ == 0)
10974     {
10975       ClutterActor *tmp = self->priv->first_child;
10976
10977       if (tmp != NULL)
10978         tmp->priv->prev_sibling = child;
10979
10980       child->priv->prev_sibling = NULL;
10981       child->priv->next_sibling = tmp;
10982     }
10983   else if (index_ < 0 || index_ >= self->priv->n_children)
10984     {
10985       ClutterActor *tmp = self->priv->last_child;
10986
10987       if (tmp != NULL)
10988         tmp->priv->next_sibling = child;
10989
10990       child->priv->prev_sibling = tmp;
10991       child->priv->next_sibling = NULL;
10992     }
10993   else
10994     {
10995       ClutterActor *iter;
10996       int i;
10997
10998       for (iter = self->priv->first_child, i = 0;
10999            iter != NULL;
11000            iter = iter->priv->next_sibling, i += 1)
11001         {
11002           if (index_ == i)
11003             {
11004               ClutterActor *tmp = iter->priv->prev_sibling;
11005
11006               child->priv->prev_sibling = tmp;
11007               child->priv->next_sibling = iter;
11008
11009               iter->priv->prev_sibling = child;
11010
11011               if (tmp != NULL)
11012                 tmp->priv->next_sibling = child;
11013
11014               break;
11015             }
11016         }
11017     }
11018
11019   if (child->priv->prev_sibling == NULL)
11020     self->priv->first_child = child;
11021
11022   if (child->priv->next_sibling == NULL)
11023     self->priv->last_child = child;
11024 }
11025
11026 static void
11027 insert_child_above (ClutterActor *self,
11028                     ClutterActor *child,
11029                     gpointer      data)
11030 {
11031   ClutterActor *sibling = data;
11032
11033   child->priv->parent = self;
11034
11035   if (sibling == NULL)
11036     sibling = self->priv->last_child;
11037
11038   child->priv->prev_sibling = sibling;
11039
11040   if (sibling != NULL)
11041     {
11042       ClutterActor *tmp = sibling->priv->next_sibling;
11043
11044       child->priv->next_sibling = tmp;
11045
11046       if (tmp != NULL)
11047         tmp->priv->prev_sibling = child;
11048
11049       sibling->priv->next_sibling = child;
11050     }
11051   else
11052     child->priv->next_sibling = NULL;
11053
11054   if (child->priv->prev_sibling == NULL)
11055     self->priv->first_child = child;
11056
11057   if (child->priv->next_sibling == NULL)
11058     self->priv->last_child = child;
11059 }
11060
11061 static void
11062 insert_child_below (ClutterActor *self,
11063                     ClutterActor *child,
11064                     gpointer      data)
11065 {
11066   ClutterActor *sibling = data;
11067
11068   child->priv->parent = self;
11069
11070   if (sibling == NULL)
11071     sibling = self->priv->first_child;
11072
11073   child->priv->next_sibling = sibling;
11074
11075   if (sibling != NULL)
11076     {
11077       ClutterActor *tmp = sibling->priv->prev_sibling;
11078
11079       child->priv->prev_sibling = tmp;
11080
11081       if (tmp != NULL)
11082         tmp->priv->next_sibling = child;
11083
11084       sibling->priv->prev_sibling = child;
11085     }
11086   else
11087     child->priv->prev_sibling = NULL;
11088
11089   if (child->priv->prev_sibling == NULL)
11090     self->priv->first_child = child;
11091
11092   if (child->priv->next_sibling == NULL)
11093     self->priv->last_child = child;
11094 }
11095
11096 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11097                                            ClutterActor *child,
11098                                            gpointer      data);
11099
11100 typedef enum {
11101   ADD_CHILD_CREATE_META        = 1 << 0,
11102   ADD_CHILD_EMIT_PARENT_SET    = 1 << 1,
11103   ADD_CHILD_EMIT_ACTOR_ADDED   = 1 << 2,
11104   ADD_CHILD_CHECK_STATE        = 1 << 3,
11105   ADD_CHILD_NOTIFY_FIRST_LAST  = 1 << 4,
11106   ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11107
11108   /* default flags for public API */
11109   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
11110                                ADD_CHILD_EMIT_PARENT_SET |
11111                                ADD_CHILD_EMIT_ACTOR_ADDED |
11112                                ADD_CHILD_CHECK_STATE |
11113                                ADD_CHILD_NOTIFY_FIRST_LAST |
11114                                ADD_CHILD_SHOW_ON_SET_PARENT,
11115
11116   /* flags for legacy/deprecated API */
11117   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
11118                                ADD_CHILD_CHECK_STATE |
11119                                ADD_CHILD_NOTIFY_FIRST_LAST |
11120                                ADD_CHILD_SHOW_ON_SET_PARENT
11121 } ClutterActorAddChildFlags;
11122
11123 /*< private >
11124  * clutter_actor_add_child_internal:
11125  * @self: a #ClutterActor
11126  * @child: a #ClutterActor
11127  * @flags: control flags for actions
11128  * @add_func: delegate function
11129  * @data: (closure): data to pass to @add_func
11130  *
11131  * Adds @child to the list of children of @self.
11132  *
11133  * The actual insertion inside the list is delegated to @add_func: this
11134  * function will just set up the state, perform basic checks, and emit
11135  * signals.
11136  *
11137  * The @flags argument is used to perform additional operations.
11138  */
11139 static inline void
11140 clutter_actor_add_child_internal (ClutterActor              *self,
11141                                   ClutterActor              *child,
11142                                   ClutterActorAddChildFlags  flags,
11143                                   ClutterActorAddChildFunc   add_func,
11144                                   gpointer                   data)
11145 {
11146   ClutterTextDirection text_dir;
11147   gboolean create_meta;
11148   gboolean emit_parent_set, emit_actor_added;
11149   gboolean check_state;
11150   gboolean notify_first_last;
11151   gboolean show_on_set_parent;
11152   ClutterActor *old_first_child, *old_last_child;
11153
11154   if (child->priv->parent != NULL)
11155     {
11156       g_warning ("The actor '%s' already has a parent, '%s'. You must "
11157                  "use clutter_actor_remove_child() first.",
11158                  _clutter_actor_get_debug_name (child),
11159                  _clutter_actor_get_debug_name (child->priv->parent));
11160       return;
11161     }
11162
11163   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11164     {
11165       g_warning ("The actor '%s' is a top-level actor, and cannot be "
11166                  "a child of another actor.",
11167                  _clutter_actor_get_debug_name (child));
11168       return;
11169     }
11170
11171 #if 0
11172   /* XXX - this check disallows calling methods that change the stacking
11173    * order within the destruction sequence, by triggering a critical
11174    * warning first, and leaving the actor in an undefined state, which
11175    * then ends up being caught by an assertion.
11176    *
11177    * the reproducible sequence is:
11178    *
11179    *   - actor gets destroyed;
11180    *   - another actor, linked to the first, will try to change the
11181    *     stacking order of the first actor;
11182    *   - changing the stacking order is a composite operation composed
11183    *     by the following steps:
11184    *     1. ref() the child;
11185    *     2. remove_child_internal(), which removes the reference;
11186    *     3. add_child_internal(), which adds a reference;
11187    *   - the state of the actor is not changed between (2) and (3), as
11188    *     it could be an expensive recomputation;
11189    *   - if (3) bails out, then the actor is in an undefined state, but
11190    *     still alive;
11191    *   - the destruction sequence terminates, but the actor is unparented
11192    *     while its state indicates being parented instead.
11193    *   - assertion failure.
11194    *
11195    * the obvious fix would be to decompose each set_child_*_sibling()
11196    * method into proper remove_child()/add_child(), with state validation;
11197    * this may cause excessive work, though, and trigger a cascade of other
11198    * bugs in code that assumes that a change in the stacking order is an
11199    * atomic operation.
11200    *
11201    * another potential fix is to just remove this check here, and let
11202    * code doing stacking order changes inside the destruction sequence
11203    * of an actor continue doing the work.
11204    *
11205    * the third fix is to silently bail out early from every
11206    * set_child_*_sibling() and set_child_at_index() method, and avoid
11207    * doing work.
11208    *
11209    * I have a preference for the second solution, since it involves the
11210    * least amount of work, and the least amount of code duplication.
11211    *
11212    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11213    */
11214   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11215     {
11216       g_warning ("The actor '%s' is currently being destroyed, and "
11217                  "cannot be added as a child of another actor.",
11218                  _clutter_actor_get_debug_name (child));
11219       return;
11220     }
11221 #endif
11222
11223   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11224   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11225   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11226   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11227   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11228   show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11229
11230   old_first_child = self->priv->first_child;
11231   old_last_child = self->priv->last_child;
11232
11233   g_object_freeze_notify (G_OBJECT (self));
11234
11235   if (create_meta)
11236     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11237
11238   g_object_ref_sink (child);
11239   child->priv->parent = NULL;
11240   child->priv->next_sibling = NULL;
11241   child->priv->prev_sibling = NULL;
11242
11243   /* delegate the actual insertion */
11244   add_func (self, child, data);
11245
11246   g_assert (child->priv->parent == self);
11247
11248   self->priv->n_children += 1;
11249
11250   self->priv->age += 1;
11251
11252   /* if push_internal() has been called then we automatically set
11253    * the flag on the actor
11254    */
11255   if (self->priv->internal_child)
11256     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11257
11258   /* clutter_actor_reparent() will emit ::parent-set for us */
11259   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11260     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11261
11262   if (check_state)
11263     {
11264       /* If parent is mapped or realized, we need to also be mapped or
11265        * realized once we're inside the parent.
11266        */
11267       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11268
11269       /* propagate the parent's text direction to the child */
11270       text_dir = clutter_actor_get_text_direction (self);
11271       clutter_actor_set_text_direction (child, text_dir);
11272     }
11273
11274   if (show_on_set_parent && child->priv->show_on_set_parent)
11275     clutter_actor_show (child);
11276
11277   if (CLUTTER_ACTOR_IS_MAPPED (child))
11278     clutter_actor_queue_redraw (child);
11279
11280   /* maintain the invariant that if an actor needs layout,
11281    * its parents do as well
11282    */
11283   if (child->priv->needs_width_request ||
11284       child->priv->needs_height_request ||
11285       child->priv->needs_allocation)
11286     {
11287       /* we work around the short-circuiting we do
11288        * in clutter_actor_queue_relayout() since we
11289        * want to force a relayout
11290        */
11291       child->priv->needs_width_request = TRUE;
11292       child->priv->needs_height_request = TRUE;
11293       child->priv->needs_allocation = TRUE;
11294
11295       clutter_actor_queue_relayout (child->priv->parent);
11296     }
11297
11298   if (emit_actor_added)
11299     g_signal_emit_by_name (self, "actor-added", child);
11300
11301   if (notify_first_last)
11302     {
11303       if (old_first_child != self->priv->first_child)
11304         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11305
11306       if (old_last_child != self->priv->last_child)
11307         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11308     }
11309
11310   g_object_thaw_notify (G_OBJECT (self));
11311 }
11312
11313 /**
11314  * clutter_actor_add_child:
11315  * @self: a #ClutterActor
11316  * @child: a #ClutterActor
11317  *
11318  * Adds @child to the children of @self.
11319  *
11320  * This function will acquire a reference on @child that will only
11321  * be released when calling clutter_actor_remove_child().
11322  *
11323  * This function will take into consideration the #ClutterActor:depth
11324  * of @child, and will keep the list of children sorted.
11325  *
11326  * This function will emit the #ClutterContainer::actor-added signal
11327  * on @self.
11328  *
11329  * Since: 1.10
11330  */
11331 void
11332 clutter_actor_add_child (ClutterActor *self,
11333                          ClutterActor *child)
11334 {
11335   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11336   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11337   g_return_if_fail (self != child);
11338   g_return_if_fail (child->priv->parent == NULL);
11339
11340   clutter_actor_add_child_internal (self, child,
11341                                     ADD_CHILD_DEFAULT_FLAGS,
11342                                     insert_child_at_depth,
11343                                     NULL);
11344 }
11345
11346 /**
11347  * clutter_actor_insert_child_at_index:
11348  * @self: a #ClutterActor
11349  * @child: a #ClutterActor
11350  * @index_: the index
11351  *
11352  * Inserts @child into the list of children of @self, using the
11353  * given @index_. If @index_ is greater than the number of children
11354  * in @self, or is less than 0, then the new child is added at the end.
11355  *
11356  * This function will acquire a reference on @child that will only
11357  * be released when calling clutter_actor_remove_child().
11358  *
11359  * This function will not take into consideration the #ClutterActor:depth
11360  * of @child.
11361  *
11362  * This function will emit the #ClutterContainer::actor-added signal
11363  * on @self.
11364  *
11365  * Since: 1.10
11366  */
11367 void
11368 clutter_actor_insert_child_at_index (ClutterActor *self,
11369                                      ClutterActor *child,
11370                                      gint          index_)
11371 {
11372   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11373   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11374   g_return_if_fail (self != child);
11375   g_return_if_fail (child->priv->parent == NULL);
11376
11377   clutter_actor_add_child_internal (self, child,
11378                                     ADD_CHILD_DEFAULT_FLAGS,
11379                                     insert_child_at_index,
11380                                     GINT_TO_POINTER (index_));
11381 }
11382
11383 /**
11384  * clutter_actor_insert_child_above:
11385  * @self: a #ClutterActor
11386  * @child: a #ClutterActor
11387  * @sibling: (allow-none): a child of @self, or %NULL
11388  *
11389  * Inserts @child into the list of children of @self, above another
11390  * child of @self or, if @sibling is %NULL, above all the children
11391  * of @self.
11392  *
11393  * This function will acquire a reference on @child that will only
11394  * be released when calling clutter_actor_remove_child().
11395  *
11396  * This function will not take into consideration the #ClutterActor:depth
11397  * of @child.
11398  *
11399  * This function will emit the #ClutterContainer::actor-added signal
11400  * on @self.
11401  *
11402  * Since: 1.10
11403  */
11404 void
11405 clutter_actor_insert_child_above (ClutterActor *self,
11406                                   ClutterActor *child,
11407                                   ClutterActor *sibling)
11408 {
11409   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11410   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11411   g_return_if_fail (self != child);
11412   g_return_if_fail (child != sibling);
11413   g_return_if_fail (child->priv->parent == NULL);
11414   g_return_if_fail (sibling == NULL ||
11415                     (CLUTTER_IS_ACTOR (sibling) &&
11416                      sibling->priv->parent == self));
11417
11418   clutter_actor_add_child_internal (self, child,
11419                                     ADD_CHILD_DEFAULT_FLAGS,
11420                                     insert_child_above,
11421                                     sibling);
11422 }
11423
11424 /**
11425  * clutter_actor_insert_child_below:
11426  * @self: a #ClutterActor
11427  * @child: a #ClutterActor
11428  * @sibling: (allow-none): a child of @self, or %NULL
11429  *
11430  * Inserts @child into the list of children of @self, below another
11431  * child of @self or, if @sibling is %NULL, below all the children
11432  * of @self.
11433  *
11434  * This function will acquire a reference on @child that will only
11435  * be released when calling clutter_actor_remove_child().
11436  *
11437  * This function will not take into consideration the #ClutterActor:depth
11438  * of @child.
11439  *
11440  * This function will emit the #ClutterContainer::actor-added signal
11441  * on @self.
11442  *
11443  * Since: 1.10
11444  */
11445 void
11446 clutter_actor_insert_child_below (ClutterActor *self,
11447                                   ClutterActor *child,
11448                                   ClutterActor *sibling)
11449 {
11450   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11451   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11452   g_return_if_fail (self != child);
11453   g_return_if_fail (child != sibling);
11454   g_return_if_fail (child->priv->parent == NULL);
11455   g_return_if_fail (sibling == NULL ||
11456                     (CLUTTER_IS_ACTOR (sibling) &&
11457                      sibling->priv->parent == self));
11458
11459   clutter_actor_add_child_internal (self, child,
11460                                     ADD_CHILD_DEFAULT_FLAGS,
11461                                     insert_child_below,
11462                                     sibling);
11463 }
11464
11465 /**
11466  * clutter_actor_set_parent:
11467  * @self: A #ClutterActor
11468  * @parent: A new #ClutterActor parent
11469  *
11470  * Sets the parent of @self to @parent.
11471  *
11472  * This function will result in @parent acquiring a reference on @self,
11473  * eventually by sinking its floating reference first. The reference
11474  * will be released by clutter_actor_unparent().
11475  *
11476  * This function should only be called by legacy #ClutterActor<!-- -->s
11477  * implementing the #ClutterContainer interface.
11478  *
11479  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11480  */
11481 void
11482 clutter_actor_set_parent (ClutterActor *self,
11483                           ClutterActor *parent)
11484 {
11485   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11486   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11487   g_return_if_fail (self != parent);
11488   g_return_if_fail (self->priv->parent == NULL);
11489
11490   /* as this function will be called inside ClutterContainer::add
11491    * implementations or when building up a composite actor, we have
11492    * to preserve the old behaviour, and not create child meta or
11493    * emit the ::actor-added signal, to avoid recursion or double
11494    * emissions
11495    */
11496   clutter_actor_add_child_internal (parent, self,
11497                                     ADD_CHILD_LEGACY_FLAGS,
11498                                     insert_child_at_depth,
11499                                     NULL);
11500 }
11501
11502 /**
11503  * clutter_actor_get_parent:
11504  * @self: A #ClutterActor
11505  *
11506  * Retrieves the parent of @self.
11507  *
11508  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11509  *  if no parent is set
11510  */
11511 ClutterActor *
11512 clutter_actor_get_parent (ClutterActor *self)
11513 {
11514   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11515
11516   return self->priv->parent;
11517 }
11518
11519 /**
11520  * clutter_actor_get_paint_visibility:
11521  * @self: A #ClutterActor
11522  *
11523  * Retrieves the 'paint' visibility of an actor recursively checking for non
11524  * visible parents.
11525  *
11526  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11527  *
11528  * Return Value: %TRUE if the actor is visibile and will be painted.
11529  *
11530  * Since: 0.8.4
11531  */
11532 gboolean
11533 clutter_actor_get_paint_visibility (ClutterActor *actor)
11534 {
11535   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11536
11537   return CLUTTER_ACTOR_IS_MAPPED (actor);
11538 }
11539
11540 /**
11541  * clutter_actor_remove_child:
11542  * @self: a #ClutterActor
11543  * @child: a #ClutterActor
11544  *
11545  * Removes @child from the children of @self.
11546  *
11547  * This function will release the reference added by
11548  * clutter_actor_add_child(), so if you want to keep using @child
11549  * you will have to acquire a referenced on it before calling this
11550  * function.
11551  *
11552  * This function will emit the #ClutterContainer::actor-removed
11553  * signal on @self.
11554  *
11555  * Since: 1.10
11556  */
11557 void
11558 clutter_actor_remove_child (ClutterActor *self,
11559                             ClutterActor *child)
11560 {
11561   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11562   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11563   g_return_if_fail (self != child);
11564   g_return_if_fail (child->priv->parent != NULL);
11565   g_return_if_fail (child->priv->parent == self);
11566
11567   clutter_actor_remove_child_internal (self, child,
11568                                        REMOVE_CHILD_DEFAULT_FLAGS);
11569 }
11570
11571 /**
11572  * clutter_actor_remove_all_children:
11573  * @self: a #ClutterActor
11574  *
11575  * Removes all children of @self.
11576  *
11577  * This function releases the reference added by inserting a child actor
11578  * in the list of children of @self.
11579  *
11580  * If the reference count of a child drops to zero, the child will be
11581  * destroyed. If you want to ensure the destruction of all the children
11582  * of @self, use clutter_actor_destroy_all_children().
11583  *
11584  * Since: 1.10
11585  */
11586 void
11587 clutter_actor_remove_all_children (ClutterActor *self)
11588 {
11589   ClutterActorIter iter;
11590
11591   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11592
11593   if (self->priv->n_children == 0)
11594     return;
11595
11596   g_object_freeze_notify (G_OBJECT (self));
11597
11598   clutter_actor_iter_init (&iter, self);
11599   while (clutter_actor_iter_next (&iter, NULL))
11600     clutter_actor_iter_remove (&iter);
11601
11602   g_object_thaw_notify (G_OBJECT (self));
11603
11604   /* sanity check */
11605   g_assert (self->priv->first_child == NULL);
11606   g_assert (self->priv->last_child == NULL);
11607   g_assert (self->priv->n_children == 0);
11608 }
11609
11610 /**
11611  * clutter_actor_destroy_all_children:
11612  * @self: a #ClutterActor
11613  *
11614  * Destroys all children of @self.
11615  *
11616  * This function releases the reference added by inserting a child
11617  * actor in the list of children of @self, and ensures that the
11618  * #ClutterActor::destroy signal is emitted on each child of the
11619  * actor.
11620  *
11621  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11622  * when its reference count drops to 0; the default handler of the
11623  * #ClutterActor::destroy signal will destroy all the children of an
11624  * actor. This function ensures that all children are destroyed, instead
11625  * of just removed from @self, unlike clutter_actor_remove_all_children()
11626  * which will merely release the reference and remove each child.
11627  *
11628  * Unless you acquired an additional reference on each child of @self
11629  * prior to calling clutter_actor_remove_all_children() and want to reuse
11630  * the actors, you should use clutter_actor_destroy_all_children() in
11631  * order to make sure that children are destroyed and signal handlers
11632  * are disconnected even in cases where circular references prevent this
11633  * from automatically happening through reference counting alone.
11634  *
11635  * Since: 1.10
11636  */
11637 void
11638 clutter_actor_destroy_all_children (ClutterActor *self)
11639 {
11640   ClutterActorIter iter;
11641
11642   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11643
11644   if (self->priv->n_children == 0)
11645     return;
11646
11647   g_object_freeze_notify (G_OBJECT (self));
11648
11649   clutter_actor_iter_init (&iter, self);
11650   while (clutter_actor_iter_next (&iter, NULL))
11651     clutter_actor_iter_destroy (&iter);
11652
11653   g_object_thaw_notify (G_OBJECT (self));
11654
11655   /* sanity check */
11656   g_assert (self->priv->first_child == NULL);
11657   g_assert (self->priv->last_child == NULL);
11658   g_assert (self->priv->n_children == 0);
11659 }
11660
11661 typedef struct _InsertBetweenData {
11662   ClutterActor *prev_sibling;
11663   ClutterActor *next_sibling;
11664 } InsertBetweenData;
11665
11666 static void
11667 insert_child_between (ClutterActor *self,
11668                       ClutterActor *child,
11669                       gpointer      data_)
11670 {
11671   InsertBetweenData *data = data_;
11672   ClutterActor *prev_sibling = data->prev_sibling;
11673   ClutterActor *next_sibling = data->next_sibling;
11674
11675   child->priv->parent = self;
11676   child->priv->prev_sibling = prev_sibling;
11677   child->priv->next_sibling = next_sibling;
11678
11679   if (prev_sibling != NULL)
11680     prev_sibling->priv->next_sibling = child;
11681
11682   if (next_sibling != NULL)
11683     next_sibling->priv->prev_sibling = child;
11684
11685   if (child->priv->prev_sibling == NULL)
11686     self->priv->first_child = child;
11687
11688   if (child->priv->next_sibling == NULL)
11689     self->priv->last_child = child;
11690 }
11691
11692 /**
11693  * clutter_actor_replace_child:
11694  * @self: a #ClutterActor
11695  * @old_child: the child of @self to replace
11696  * @new_child: the #ClutterActor to replace @old_child
11697  *
11698  * Replaces @old_child with @new_child in the list of children of @self.
11699  *
11700  * Since: 1.10
11701  */
11702 void
11703 clutter_actor_replace_child (ClutterActor *self,
11704                              ClutterActor *old_child,
11705                              ClutterActor *new_child)
11706 {
11707   ClutterActor *prev_sibling, *next_sibling;
11708   InsertBetweenData clos;
11709
11710   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11711   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11712   g_return_if_fail (old_child->priv->parent == self);
11713   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11714   g_return_if_fail (old_child != new_child);
11715   g_return_if_fail (new_child != self);
11716   g_return_if_fail (new_child->priv->parent == NULL);
11717
11718   prev_sibling = old_child->priv->prev_sibling;
11719   next_sibling = old_child->priv->next_sibling;
11720   clutter_actor_remove_child_internal (self, old_child,
11721                                        REMOVE_CHILD_DEFAULT_FLAGS);
11722
11723   clos.prev_sibling = prev_sibling;
11724   clos.next_sibling = next_sibling;
11725   clutter_actor_add_child_internal (self, new_child,
11726                                     ADD_CHILD_DEFAULT_FLAGS,
11727                                     insert_child_between,
11728                                     &clos);
11729 }
11730
11731 /**
11732  * clutter_actor_unparent:
11733  * @self: a #ClutterActor
11734  *
11735  * Removes the parent of @self.
11736  *
11737  * This will cause the parent of @self to release the reference
11738  * acquired when calling clutter_actor_set_parent(), so if you
11739  * want to keep @self you will have to acquire a reference of
11740  * your own, through g_object_ref().
11741  *
11742  * This function should only be called by legacy #ClutterActor<!-- -->s
11743  * implementing the #ClutterContainer interface.
11744  *
11745  * Since: 0.1.1
11746  *
11747  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11748  */
11749 void
11750 clutter_actor_unparent (ClutterActor *self)
11751 {
11752   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11753
11754   if (self->priv->parent == NULL)
11755     return;
11756
11757   clutter_actor_remove_child_internal (self->priv->parent, self,
11758                                        REMOVE_CHILD_LEGACY_FLAGS);
11759 }
11760
11761 /**
11762  * clutter_actor_reparent:
11763  * @self: a #ClutterActor
11764  * @new_parent: the new #ClutterActor parent
11765  *
11766  * Resets the parent actor of @self.
11767  *
11768  * This function is logically equivalent to calling clutter_actor_unparent()
11769  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11770  * ensures the child is not finalized when unparented, and emits the
11771  * #ClutterActor::parent-set signal only once.
11772  *
11773  * In reality, calling this function is less useful than it sounds, as some
11774  * application code may rely on changes in the intermediate state between
11775  * removal and addition of the actor from its old parent to the @new_parent.
11776  * Thus, it is strongly encouraged to avoid using this function in application
11777  * code.
11778  *
11779  * Since: 0.2
11780  *
11781  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11782  *   clutter_actor_add_child() instead; remember to take a reference on
11783  *   the actor being removed before calling clutter_actor_remove_child()
11784  *   to avoid the reference count dropping to zero and the actor being
11785  *   destroyed.
11786  */
11787 void
11788 clutter_actor_reparent (ClutterActor *self,
11789                         ClutterActor *new_parent)
11790 {
11791   ClutterActorPrivate *priv;
11792
11793   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11794   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11795   g_return_if_fail (self != new_parent);
11796
11797   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11798     {
11799       g_warning ("Cannot set a parent on a toplevel actor");
11800       return;
11801     }
11802
11803   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11804     {
11805       g_warning ("Cannot set a parent currently being destroyed");
11806       return;
11807     }
11808
11809   priv = self->priv;
11810
11811   if (priv->parent != new_parent)
11812     {
11813       ClutterActor *old_parent;
11814
11815       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11816
11817       old_parent = priv->parent;
11818
11819       g_object_ref (self);
11820
11821       if (old_parent != NULL)
11822         {
11823          /* go through the Container implementation if this is a regular
11824           * child and not an internal one
11825           */
11826          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11827            {
11828              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11829
11830              /* this will have to call unparent() */
11831              clutter_container_remove_actor (parent, self);
11832            }
11833          else
11834            clutter_actor_remove_child_internal (old_parent, self,
11835                                                 REMOVE_CHILD_LEGACY_FLAGS);
11836         }
11837
11838       /* Note, will call set_parent() */
11839       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11840         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11841       else
11842         clutter_actor_add_child_internal (new_parent, self,
11843                                           ADD_CHILD_LEGACY_FLAGS,
11844                                           insert_child_at_depth,
11845                                           NULL);
11846
11847       /* we emit the ::parent-set signal once */
11848       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11849
11850       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11851
11852       /* the IN_REPARENT flag suspends state updates */
11853       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11854
11855       g_object_unref (self);
11856    }
11857 }
11858
11859 /**
11860  * clutter_actor_contains:
11861  * @self: A #ClutterActor
11862  * @descendant: A #ClutterActor, possibly contained in @self
11863  *
11864  * Determines if @descendant is contained inside @self (either as an
11865  * immediate child, or as a deeper descendant). If @self and
11866  * @descendant point to the same actor then it will also return %TRUE.
11867  *
11868  * Return value: whether @descendent is contained within @self
11869  *
11870  * Since: 1.4
11871  */
11872 gboolean
11873 clutter_actor_contains (ClutterActor *self,
11874                         ClutterActor *descendant)
11875 {
11876   ClutterActor *actor;
11877
11878   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11879   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11880
11881   for (actor = descendant; actor; actor = actor->priv->parent)
11882     if (actor == self)
11883       return TRUE;
11884
11885   return FALSE;
11886 }
11887
11888 /**
11889  * clutter_actor_set_child_above_sibling:
11890  * @self: a #ClutterActor
11891  * @child: a #ClutterActor child of @self
11892  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11893  *
11894  * Sets @child to be above @sibling in the list of children of @self.
11895  *
11896  * If @sibling is %NULL, @child will be the new last child of @self.
11897  *
11898  * This function is logically equivalent to removing @child and using
11899  * clutter_actor_insert_child_above(), but it will not emit signals
11900  * or change state on @child.
11901  *
11902  * Since: 1.10
11903  */
11904 void
11905 clutter_actor_set_child_above_sibling (ClutterActor *self,
11906                                        ClutterActor *child,
11907                                        ClutterActor *sibling)
11908 {
11909   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11910   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11911   g_return_if_fail (child->priv->parent == self);
11912   g_return_if_fail (child != sibling);
11913   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11914
11915   if (sibling != NULL)
11916     g_return_if_fail (sibling->priv->parent == self);
11917
11918   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11919       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11920       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11921     return;
11922
11923   /* we don't want to change the state of child, or emit signals, or
11924    * regenerate ChildMeta instances here, but we still want to follow
11925    * the correct sequence of steps encoded in remove_child() and
11926    * add_child(), so that correctness is ensured, and we only go
11927    * through one known code path.
11928    */
11929   g_object_ref (child);
11930   clutter_actor_remove_child_internal (self, child, 0);
11931   clutter_actor_add_child_internal (self, child,
11932                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11933                                     insert_child_above,
11934                                     sibling);
11935
11936   clutter_actor_queue_relayout (self);
11937 }
11938
11939 /**
11940  * clutter_actor_set_child_below_sibling:
11941  * @self: a #ClutterActor
11942  * @child: a #ClutterActor child of @self
11943  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11944  *
11945  * Sets @child to be below @sibling in the list of children of @self.
11946  *
11947  * If @sibling is %NULL, @child will be the new first child of @self.
11948  *
11949  * This function is logically equivalent to removing @self and using
11950  * clutter_actor_insert_child_below(), but it will not emit signals
11951  * or change state on @child.
11952  *
11953  * Since: 1.10
11954  */
11955 void
11956 clutter_actor_set_child_below_sibling (ClutterActor *self,
11957                                        ClutterActor *child,
11958                                        ClutterActor *sibling)
11959 {
11960   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11961   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11962   g_return_if_fail (child->priv->parent == self);
11963   g_return_if_fail (child != sibling);
11964   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11965
11966   if (sibling != NULL)
11967     g_return_if_fail (sibling->priv->parent == self);
11968
11969   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11970       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11971       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11972     return;
11973
11974   /* see the comment in set_child_above_sibling() */
11975   g_object_ref (child);
11976   clutter_actor_remove_child_internal (self, child, 0);
11977   clutter_actor_add_child_internal (self, child,
11978                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11979                                     insert_child_below,
11980                                     sibling);
11981
11982   clutter_actor_queue_relayout (self);
11983 }
11984
11985 /**
11986  * clutter_actor_set_child_at_index:
11987  * @self: a #ClutterActor
11988  * @child: a #ClutterActor child of @self
11989  * @index_: the new index for @child
11990  *
11991  * Changes the index of @child in the list of children of @self.
11992  *
11993  * This function is logically equivalent to removing @child and
11994  * calling clutter_actor_insert_child_at_index(), but it will not
11995  * emit signals or change state on @child.
11996  *
11997  * Since: 1.10
11998  */
11999 void
12000 clutter_actor_set_child_at_index (ClutterActor *self,
12001                                   ClutterActor *child,
12002                                   gint          index_)
12003 {
12004   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12005   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12006   g_return_if_fail (child->priv->parent == self);
12007   g_return_if_fail (index_ <= self->priv->n_children);
12008
12009   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12010       CLUTTER_ACTOR_IN_DESTRUCTION (child))
12011     return;
12012
12013   g_object_ref (child);
12014   clutter_actor_remove_child_internal (self, child, 0);
12015   clutter_actor_add_child_internal (self, child,
12016                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12017                                     insert_child_at_index,
12018                                     GINT_TO_POINTER (index_));
12019
12020   clutter_actor_queue_relayout (self);
12021 }
12022
12023 /**
12024  * clutter_actor_raise:
12025  * @self: A #ClutterActor
12026  * @below: (allow-none): A #ClutterActor to raise above.
12027  *
12028  * Puts @self above @below.
12029  *
12030  * Both actors must have the same parent, and the parent must implement
12031  * the #ClutterContainer interface
12032  *
12033  * This function calls clutter_container_raise_child() internally.
12034  *
12035  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12036  */
12037 void
12038 clutter_actor_raise (ClutterActor *self,
12039                      ClutterActor *below)
12040 {
12041   ClutterActor *parent;
12042
12043   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12044
12045   parent = clutter_actor_get_parent (self);
12046   if (parent == NULL)
12047     {
12048       g_warning ("%s: Actor '%s' is not inside a container",
12049                  G_STRFUNC,
12050                  _clutter_actor_get_debug_name (self));
12051       return;
12052     }
12053
12054   if (below != NULL)
12055     {
12056       if (parent != clutter_actor_get_parent (below))
12057         {
12058           g_warning ("%s Actor '%s' is not in the same container as "
12059                      "actor '%s'",
12060                      G_STRFUNC,
12061                      _clutter_actor_get_debug_name (self),
12062                      _clutter_actor_get_debug_name (below));
12063           return;
12064         }
12065     }
12066
12067   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12068 }
12069
12070 /**
12071  * clutter_actor_lower:
12072  * @self: A #ClutterActor
12073  * @above: (allow-none): A #ClutterActor to lower below
12074  *
12075  * Puts @self below @above.
12076  *
12077  * Both actors must have the same parent, and the parent must implement
12078  * the #ClutterContainer interface.
12079  *
12080  * This function calls clutter_container_lower_child() internally.
12081  *
12082  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12083  */
12084 void
12085 clutter_actor_lower (ClutterActor *self,
12086                      ClutterActor *above)
12087 {
12088   ClutterActor *parent;
12089
12090   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12091
12092   parent = clutter_actor_get_parent (self);
12093   if (parent == NULL)
12094     {
12095       g_warning ("%s: Actor of type %s is not inside a container",
12096                  G_STRFUNC,
12097                  _clutter_actor_get_debug_name (self));
12098       return;
12099     }
12100
12101   if (above)
12102     {
12103       if (parent != clutter_actor_get_parent (above))
12104         {
12105           g_warning ("%s: Actor '%s' is not in the same container as "
12106                      "actor '%s'",
12107                      G_STRFUNC,
12108                      _clutter_actor_get_debug_name (self),
12109                      _clutter_actor_get_debug_name (above));
12110           return;
12111         }
12112     }
12113
12114   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12115 }
12116
12117 /**
12118  * clutter_actor_raise_top:
12119  * @self: A #ClutterActor
12120  *
12121  * Raises @self to the top.
12122  *
12123  * This function calls clutter_actor_raise() internally.
12124  *
12125  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12126  *   a %NULL sibling, instead.
12127  */
12128 void
12129 clutter_actor_raise_top (ClutterActor *self)
12130 {
12131   clutter_actor_raise (self, NULL);
12132 }
12133
12134 /**
12135  * clutter_actor_lower_bottom:
12136  * @self: A #ClutterActor
12137  *
12138  * Lowers @self to the bottom.
12139  *
12140  * This function calls clutter_actor_lower() internally.
12141  *
12142  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12143  *   a %NULL sibling, instead.
12144  */
12145 void
12146 clutter_actor_lower_bottom (ClutterActor *self)
12147 {
12148   clutter_actor_lower (self, NULL);
12149 }
12150
12151 /*
12152  * Event handling
12153  */
12154
12155 /**
12156  * clutter_actor_event:
12157  * @actor: a #ClutterActor
12158  * @event: a #ClutterEvent
12159  * @capture: TRUE if event in in capture phase, FALSE otherwise.
12160  *
12161  * This function is used to emit an event on the main stage.
12162  * You should rarely need to use this function, except for
12163  * synthetising events.
12164  *
12165  * Return value: the return value from the signal emission: %TRUE
12166  *   if the actor handled the event, or %FALSE if the event was
12167  *   not handled
12168  *
12169  * Since: 0.6
12170  */
12171 gboolean
12172 clutter_actor_event (ClutterActor *actor,
12173                      ClutterEvent *event,
12174                      gboolean      capture)
12175 {
12176   gboolean retval = FALSE;
12177   gint signal_num = -1;
12178
12179   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12180   g_return_val_if_fail (event != NULL, FALSE);
12181
12182   g_object_ref (actor);
12183
12184   if (capture)
12185     {
12186       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12187                      event,
12188                      &retval);
12189       goto out;
12190     }
12191
12192   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12193
12194   if (!retval)
12195     {
12196       switch (event->type)
12197         {
12198         case CLUTTER_NOTHING:
12199           break;
12200         case CLUTTER_BUTTON_PRESS:
12201           signal_num = BUTTON_PRESS_EVENT;
12202           break;
12203         case CLUTTER_BUTTON_RELEASE:
12204           signal_num = BUTTON_RELEASE_EVENT;
12205           break;
12206         case CLUTTER_SCROLL:
12207           signal_num = SCROLL_EVENT;
12208           break;
12209         case CLUTTER_KEY_PRESS:
12210           signal_num = KEY_PRESS_EVENT;
12211           break;
12212         case CLUTTER_KEY_RELEASE:
12213           signal_num = KEY_RELEASE_EVENT;
12214           break;
12215         case CLUTTER_MOTION:
12216           signal_num = MOTION_EVENT;
12217           break;
12218         case CLUTTER_ENTER:
12219           signal_num = ENTER_EVENT;
12220           break;
12221         case CLUTTER_LEAVE:
12222           signal_num = LEAVE_EVENT;
12223           break;
12224         case CLUTTER_DELETE:
12225         case CLUTTER_DESTROY_NOTIFY:
12226         case CLUTTER_CLIENT_MESSAGE:
12227         default:
12228           signal_num = -1;
12229           break;
12230         }
12231
12232       if (signal_num != -1)
12233         g_signal_emit (actor, actor_signals[signal_num], 0,
12234                        event, &retval);
12235     }
12236
12237 out:
12238   g_object_unref (actor);
12239
12240   return retval;
12241 }
12242
12243 /**
12244  * clutter_actor_set_reactive:
12245  * @actor: a #ClutterActor
12246  * @reactive: whether the actor should be reactive to events
12247  *
12248  * Sets @actor as reactive. Reactive actors will receive events.
12249  *
12250  * Since: 0.6
12251  */
12252 void
12253 clutter_actor_set_reactive (ClutterActor *actor,
12254                             gboolean      reactive)
12255 {
12256   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12257
12258   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12259     return;
12260
12261   if (reactive)
12262     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12263   else
12264     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12265
12266   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12267 }
12268
12269 /**
12270  * clutter_actor_get_reactive:
12271  * @actor: a #ClutterActor
12272  *
12273  * Checks whether @actor is marked as reactive.
12274  *
12275  * Return value: %TRUE if the actor is reactive
12276  *
12277  * Since: 0.6
12278  */
12279 gboolean
12280 clutter_actor_get_reactive (ClutterActor *actor)
12281 {
12282   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12283
12284   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12285 }
12286
12287 /**
12288  * clutter_actor_get_anchor_point:
12289  * @self: a #ClutterActor
12290  * @anchor_x: (out): return location for the X coordinate of the anchor point
12291  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12292  *
12293  * Gets the current anchor point of the @actor in pixels.
12294  *
12295  * Since: 0.6
12296  */
12297 void
12298 clutter_actor_get_anchor_point (ClutterActor *self,
12299                                 gfloat       *anchor_x,
12300                                 gfloat       *anchor_y)
12301 {
12302   const ClutterTransformInfo *info;
12303
12304   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12305
12306   info = _clutter_actor_get_transform_info_or_defaults (self);
12307   clutter_anchor_coord_get_units (self, &info->anchor,
12308                                   anchor_x,
12309                                   anchor_y,
12310                                   NULL);
12311 }
12312
12313 /**
12314  * clutter_actor_set_anchor_point:
12315  * @self: a #ClutterActor
12316  * @anchor_x: X coordinate of the anchor point
12317  * @anchor_y: Y coordinate of the anchor point
12318  *
12319  * Sets an anchor point for @self. The anchor point is a point in the
12320  * coordinate space of an actor to which the actor position within its
12321  * parent is relative; the default is (0, 0), i.e. the top-left corner
12322  * of the actor.
12323  *
12324  * Since: 0.6
12325  */
12326 void
12327 clutter_actor_set_anchor_point (ClutterActor *self,
12328                                 gfloat        anchor_x,
12329                                 gfloat        anchor_y)
12330 {
12331   ClutterTransformInfo *info;
12332   ClutterActorPrivate *priv;
12333   gboolean changed = FALSE;
12334   gfloat old_anchor_x, old_anchor_y;
12335   GObject *obj;
12336
12337   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12338
12339   obj = G_OBJECT (self);
12340   priv = self->priv;
12341   info = _clutter_actor_get_transform_info (self);
12342
12343   g_object_freeze_notify (obj);
12344
12345   clutter_anchor_coord_get_units (self, &info->anchor,
12346                                   &old_anchor_x,
12347                                   &old_anchor_y,
12348                                   NULL);
12349
12350   if (info->anchor.is_fractional)
12351     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12352
12353   if (old_anchor_x != anchor_x)
12354     {
12355       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12356       changed = TRUE;
12357     }
12358
12359   if (old_anchor_y != anchor_y)
12360     {
12361       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12362       changed = TRUE;
12363     }
12364
12365   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12366
12367   if (changed)
12368     {
12369       priv->transform_valid = FALSE;
12370       clutter_actor_queue_redraw (self);
12371     }
12372
12373   g_object_thaw_notify (obj);
12374 }
12375
12376 /**
12377  * clutter_actor_get_anchor_point_gravity:
12378  * @self: a #ClutterActor
12379  *
12380  * Retrieves the anchor position expressed as a #ClutterGravity. If
12381  * the anchor point was specified using pixels or units this will
12382  * return %CLUTTER_GRAVITY_NONE.
12383  *
12384  * Return value: the #ClutterGravity used by the anchor point
12385  *
12386  * Since: 1.0
12387  */
12388 ClutterGravity
12389 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12390 {
12391   const ClutterTransformInfo *info;
12392
12393   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12394
12395   info = _clutter_actor_get_transform_info_or_defaults (self);
12396
12397   return clutter_anchor_coord_get_gravity (&info->anchor);
12398 }
12399
12400 /**
12401  * clutter_actor_move_anchor_point:
12402  * @self: a #ClutterActor
12403  * @anchor_x: X coordinate of the anchor point
12404  * @anchor_y: Y coordinate of the anchor point
12405  *
12406  * Sets an anchor point for the actor, and adjusts the actor postion so that
12407  * the relative position of the actor toward its parent remains the same.
12408  *
12409  * Since: 0.6
12410  */
12411 void
12412 clutter_actor_move_anchor_point (ClutterActor *self,
12413                                  gfloat        anchor_x,
12414                                  gfloat        anchor_y)
12415 {
12416   gfloat old_anchor_x, old_anchor_y;
12417   const ClutterTransformInfo *info;
12418
12419   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12420
12421   info = _clutter_actor_get_transform_info (self);
12422   clutter_anchor_coord_get_units (self, &info->anchor,
12423                                   &old_anchor_x,
12424                                   &old_anchor_y,
12425                                   NULL);
12426
12427   g_object_freeze_notify (G_OBJECT (self));
12428
12429   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12430
12431   if (self->priv->position_set)
12432     clutter_actor_move_by (self,
12433                            anchor_x - old_anchor_x,
12434                            anchor_y - old_anchor_y);
12435
12436   g_object_thaw_notify (G_OBJECT (self));
12437 }
12438
12439 /**
12440  * clutter_actor_move_anchor_point_from_gravity:
12441  * @self: a #ClutterActor
12442  * @gravity: #ClutterGravity.
12443  *
12444  * Sets an anchor point on the actor based on the given gravity, adjusting the
12445  * actor postion so that its relative position within its parent remains
12446  * unchanged.
12447  *
12448  * Since version 1.0 the anchor point will be stored as a gravity so
12449  * that if the actor changes size then the anchor point will move. For
12450  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12451  * and later double the size of the actor, the anchor point will move
12452  * to the bottom right.
12453  *
12454  * Since: 0.6
12455  */
12456 void
12457 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12458                                               ClutterGravity  gravity)
12459 {
12460   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12461   const ClutterTransformInfo *info;
12462   ClutterActorPrivate *priv;
12463
12464   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12465
12466   priv = self->priv;
12467   info = _clutter_actor_get_transform_info (self);
12468
12469   g_object_freeze_notify (G_OBJECT (self));
12470
12471   clutter_anchor_coord_get_units (self, &info->anchor,
12472                                   &old_anchor_x,
12473                                   &old_anchor_y,
12474                                   NULL);
12475   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12476   clutter_anchor_coord_get_units (self, &info->anchor,
12477                                   &new_anchor_x,
12478                                   &new_anchor_y,
12479                                   NULL);
12480
12481   if (priv->position_set)
12482     clutter_actor_move_by (self,
12483                            new_anchor_x - old_anchor_x,
12484                            new_anchor_y - old_anchor_y);
12485
12486   g_object_thaw_notify (G_OBJECT (self));
12487 }
12488
12489 /**
12490  * clutter_actor_set_anchor_point_from_gravity:
12491  * @self: a #ClutterActor
12492  * @gravity: #ClutterGravity.
12493  *
12494  * Sets an anchor point on the actor, based on the given gravity (this is a
12495  * convenience function wrapping clutter_actor_set_anchor_point()).
12496  *
12497  * Since version 1.0 the anchor point will be stored as a gravity so
12498  * that if the actor changes size then the anchor point will move. For
12499  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12500  * and later double the size of the actor, the anchor point will move
12501  * to the bottom right.
12502  *
12503  * Since: 0.6
12504  */
12505 void
12506 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12507                                              ClutterGravity  gravity)
12508 {
12509   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12510
12511   if (gravity == CLUTTER_GRAVITY_NONE)
12512     clutter_actor_set_anchor_point (self, 0, 0);
12513   else
12514     {
12515       GObject *obj = G_OBJECT (self);
12516       ClutterTransformInfo *info;
12517
12518       g_object_freeze_notify (obj);
12519
12520       info = _clutter_actor_get_transform_info (self);
12521       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12522
12523       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12524       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12525       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12526
12527       self->priv->transform_valid = FALSE;
12528
12529       clutter_actor_queue_redraw (self);
12530
12531       g_object_thaw_notify (obj);
12532     }
12533 }
12534
12535 static void
12536 clutter_actor_store_content_box (ClutterActor *self,
12537                                  const ClutterActorBox *box)
12538 {
12539   if (box != NULL)
12540     {
12541       self->priv->content_box = *box;
12542       self->priv->content_box_valid = TRUE;
12543     }
12544   else
12545     self->priv->content_box_valid = FALSE;
12546
12547   clutter_actor_queue_redraw (self);
12548
12549   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12550 }
12551
12552 static void
12553 clutter_container_iface_init (ClutterContainerIface *iface)
12554 {
12555   /* we don't override anything, as ClutterContainer already has a default
12556    * implementation that we can use, and which calls into our own API.
12557    */
12558 }
12559
12560 typedef enum
12561 {
12562   PARSE_X,
12563   PARSE_Y,
12564   PARSE_WIDTH,
12565   PARSE_HEIGHT,
12566   PARSE_ANCHOR_X,
12567   PARSE_ANCHOR_Y
12568 } ParseDimension;
12569
12570 static gfloat
12571 parse_units (ClutterActor   *self,
12572              ParseDimension  dimension,
12573              JsonNode       *node)
12574 {
12575   GValue value = G_VALUE_INIT;
12576   gfloat retval = 0;
12577
12578   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12579     return 0;
12580
12581   json_node_get_value (node, &value);
12582
12583   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12584     {
12585       retval = (gfloat) g_value_get_int64 (&value);
12586     }
12587   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12588     {
12589       retval = g_value_get_double (&value);
12590     }
12591   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12592     {
12593       ClutterUnits units;
12594       gboolean res;
12595
12596       res = clutter_units_from_string (&units, g_value_get_string (&value));
12597       if (res)
12598         retval = clutter_units_to_pixels (&units);
12599       else
12600         {
12601           g_warning ("Invalid value '%s': integers, strings or floating point "
12602                      "values can be used for the x, y, width and height "
12603                      "properties. Valid modifiers for strings are 'px', 'mm', "
12604                      "'pt' and 'em'.",
12605                      g_value_get_string (&value));
12606           retval = 0;
12607         }
12608     }
12609   else
12610     {
12611       g_warning ("Invalid value of type '%s': integers, strings of floating "
12612                  "point values can be used for the x, y, width, height "
12613                  "anchor-x and anchor-y properties.",
12614                  g_type_name (G_VALUE_TYPE (&value)));
12615     }
12616
12617   g_value_unset (&value);
12618
12619   return retval;
12620 }
12621
12622 typedef struct {
12623   ClutterRotateAxis axis;
12624
12625   gdouble angle;
12626
12627   gfloat center_x;
12628   gfloat center_y;
12629   gfloat center_z;
12630 } RotationInfo;
12631
12632 static inline gboolean
12633 parse_rotation_array (ClutterActor *actor,
12634                       JsonArray    *array,
12635                       RotationInfo *info)
12636 {
12637   JsonNode *element;
12638
12639   if (json_array_get_length (array) != 2)
12640     return FALSE;
12641
12642   /* angle */
12643   element = json_array_get_element (array, 0);
12644   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12645     info->angle = json_node_get_double (element);
12646   else
12647     return FALSE;
12648
12649   /* center */
12650   element = json_array_get_element (array, 1);
12651   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12652     {
12653       JsonArray *center = json_node_get_array (element);
12654
12655       if (json_array_get_length (center) != 2)
12656         return FALSE;
12657
12658       switch (info->axis)
12659         {
12660         case CLUTTER_X_AXIS:
12661           info->center_y = parse_units (actor, PARSE_Y,
12662                                         json_array_get_element (center, 0));
12663           info->center_z = parse_units (actor, PARSE_Y,
12664                                         json_array_get_element (center, 1));
12665           return TRUE;
12666
12667         case CLUTTER_Y_AXIS:
12668           info->center_x = parse_units (actor, PARSE_X,
12669                                         json_array_get_element (center, 0));
12670           info->center_z = parse_units (actor, PARSE_X,
12671                                         json_array_get_element (center, 1));
12672           return TRUE;
12673
12674         case CLUTTER_Z_AXIS:
12675           info->center_x = parse_units (actor, PARSE_X,
12676                                         json_array_get_element (center, 0));
12677           info->center_y = parse_units (actor, PARSE_Y,
12678                                         json_array_get_element (center, 1));
12679           return TRUE;
12680         }
12681     }
12682
12683   return FALSE;
12684 }
12685
12686 static gboolean
12687 parse_rotation (ClutterActor *actor,
12688                 JsonNode     *node,
12689                 RotationInfo *info)
12690 {
12691   JsonArray *array;
12692   guint len, i;
12693   gboolean retval = FALSE;
12694
12695   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12696     {
12697       g_warning ("Invalid node of type '%s' found, expecting an array",
12698                  json_node_type_name (node));
12699       return FALSE;
12700     }
12701
12702   array = json_node_get_array (node);
12703   len = json_array_get_length (array);
12704
12705   for (i = 0; i < len; i++)
12706     {
12707       JsonNode *element = json_array_get_element (array, i);
12708       JsonObject *object;
12709       JsonNode *member;
12710
12711       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12712         {
12713           g_warning ("Invalid node of type '%s' found, expecting an object",
12714                      json_node_type_name (element));
12715           return FALSE;
12716         }
12717
12718       object = json_node_get_object (element);
12719
12720       if (json_object_has_member (object, "x-axis"))
12721         {
12722           member = json_object_get_member (object, "x-axis");
12723
12724           info->axis = CLUTTER_X_AXIS;
12725
12726           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12727             {
12728               info->angle = json_node_get_double (member);
12729               retval = TRUE;
12730             }
12731           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12732             retval = parse_rotation_array (actor,
12733                                            json_node_get_array (member),
12734                                            info);
12735           else
12736             retval = FALSE;
12737         }
12738       else if (json_object_has_member (object, "y-axis"))
12739         {
12740           member = json_object_get_member (object, "y-axis");
12741
12742           info->axis = CLUTTER_Y_AXIS;
12743
12744           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12745             {
12746               info->angle = json_node_get_double (member);
12747               retval = TRUE;
12748             }
12749           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12750             retval = parse_rotation_array (actor,
12751                                            json_node_get_array (member),
12752                                            info);
12753           else
12754             retval = FALSE;
12755         }
12756       else if (json_object_has_member (object, "z-axis"))
12757         {
12758           member = json_object_get_member (object, "z-axis");
12759
12760           info->axis = CLUTTER_Z_AXIS;
12761
12762           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12763             {
12764               info->angle = json_node_get_double (member);
12765               retval = TRUE;
12766             }
12767           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12768             retval = parse_rotation_array (actor,
12769                                            json_node_get_array (member),
12770                                            info);
12771           else
12772             retval = FALSE;
12773         }
12774     }
12775
12776   return retval;
12777 }
12778
12779 static GSList *
12780 parse_actor_metas (ClutterScript *script,
12781                    ClutterActor  *actor,
12782                    JsonNode      *node)
12783 {
12784   GList *elements, *l;
12785   GSList *retval = NULL;
12786
12787   if (!JSON_NODE_HOLDS_ARRAY (node))
12788     return NULL;
12789
12790   elements = json_array_get_elements (json_node_get_array (node));
12791
12792   for (l = elements; l != NULL; l = l->next)
12793     {
12794       JsonNode *element = l->data;
12795       const gchar *id_ = _clutter_script_get_id_from_node (element);
12796       GObject *meta;
12797
12798       if (id_ == NULL || *id_ == '\0')
12799         continue;
12800
12801       meta = clutter_script_get_object (script, id_);
12802       if (meta == NULL)
12803         continue;
12804
12805       retval = g_slist_prepend (retval, meta);
12806     }
12807
12808   g_list_free (elements);
12809
12810   return g_slist_reverse (retval);
12811 }
12812
12813 static GSList *
12814 parse_behaviours (ClutterScript *script,
12815                   ClutterActor  *actor,
12816                   JsonNode      *node)
12817 {
12818   GList *elements, *l;
12819   GSList *retval = NULL;
12820
12821   if (!JSON_NODE_HOLDS_ARRAY (node))
12822     return NULL;
12823
12824   elements = json_array_get_elements (json_node_get_array (node));
12825
12826   for (l = elements; l != NULL; l = l->next)
12827     {
12828       JsonNode *element = l->data;
12829       const gchar *id_ = _clutter_script_get_id_from_node (element);
12830       GObject *behaviour;
12831
12832       if (id_ == NULL || *id_ == '\0')
12833         continue;
12834
12835       behaviour = clutter_script_get_object (script, id_);
12836       if (behaviour == NULL)
12837         continue;
12838
12839       retval = g_slist_prepend (retval, behaviour);
12840     }
12841
12842   g_list_free (elements);
12843
12844   return g_slist_reverse (retval);
12845 }
12846
12847 static gboolean
12848 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12849                                  ClutterScript     *script,
12850                                  GValue            *value,
12851                                  const gchar       *name,
12852                                  JsonNode          *node)
12853 {
12854   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12855   gboolean retval = FALSE;
12856
12857   if ((name[0] == 'x' && name[1] == '\0') ||
12858       (name[0] == 'y' && name[1] == '\0') ||
12859       (strcmp (name, "width") == 0) ||
12860       (strcmp (name, "height") == 0) ||
12861       (strcmp (name, "anchor_x") == 0) ||
12862       (strcmp (name, "anchor_y") == 0))
12863     {
12864       ParseDimension dimension;
12865       gfloat units;
12866
12867       if (name[0] == 'x')
12868         dimension = PARSE_X;
12869       else if (name[0] == 'y')
12870         dimension = PARSE_Y;
12871       else if (name[0] == 'w')
12872         dimension = PARSE_WIDTH;
12873       else if (name[0] == 'h')
12874         dimension = PARSE_HEIGHT;
12875       else if (name[0] == 'a' && name[7] == 'x')
12876         dimension = PARSE_ANCHOR_X;
12877       else if (name[0] == 'a' && name[7] == 'y')
12878         dimension = PARSE_ANCHOR_Y;
12879       else
12880         return FALSE;
12881
12882       units = parse_units (actor, dimension, node);
12883
12884       /* convert back to pixels: all properties are pixel-based */
12885       g_value_init (value, G_TYPE_FLOAT);
12886       g_value_set_float (value, units);
12887
12888       retval = TRUE;
12889     }
12890   else if (strcmp (name, "rotation") == 0)
12891     {
12892       RotationInfo *info;
12893
12894       info = g_slice_new0 (RotationInfo);
12895       retval = parse_rotation (actor, node, info);
12896
12897       if (retval)
12898         {
12899           g_value_init (value, G_TYPE_POINTER);
12900           g_value_set_pointer (value, info);
12901         }
12902       else
12903         g_slice_free (RotationInfo, info);
12904     }
12905   else if (strcmp (name, "behaviours") == 0)
12906     {
12907       GSList *l;
12908
12909 #ifdef CLUTTER_ENABLE_DEBUG
12910       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12911         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12912                                      "and it should not be used in newly "
12913                                      "written ClutterScript definitions.");
12914 #endif
12915
12916       l = parse_behaviours (script, actor, node);
12917
12918       g_value_init (value, G_TYPE_POINTER);
12919       g_value_set_pointer (value, l);
12920
12921       retval = TRUE;
12922     }
12923   else if (strcmp (name, "actions") == 0 ||
12924            strcmp (name, "constraints") == 0 ||
12925            strcmp (name, "effects") == 0)
12926     {
12927       GSList *l;
12928
12929       l = parse_actor_metas (script, actor, node);
12930
12931       g_value_init (value, G_TYPE_POINTER);
12932       g_value_set_pointer (value, l);
12933
12934       retval = TRUE;
12935     }
12936
12937   return retval;
12938 }
12939
12940 static void
12941 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12942                                    ClutterScript     *script,
12943                                    const gchar       *name,
12944                                    const GValue      *value)
12945 {
12946   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12947
12948 #ifdef CLUTTER_ENABLE_DEBUG
12949   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12950     {
12951       gchar *tmp = g_strdup_value_contents (value);
12952
12953       CLUTTER_NOTE (SCRIPT,
12954                     "in ClutterActor::set_custom_property('%s') = %s",
12955                     name,
12956                     tmp);
12957
12958       g_free (tmp);
12959     }
12960 #endif /* CLUTTER_ENABLE_DEBUG */
12961
12962   if (strcmp (name, "rotation") == 0)
12963     {
12964       RotationInfo *info;
12965
12966       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12967         return;
12968
12969       info = g_value_get_pointer (value);
12970
12971       clutter_actor_set_rotation (actor,
12972                                   info->axis, info->angle,
12973                                   info->center_x,
12974                                   info->center_y,
12975                                   info->center_z);
12976
12977       g_slice_free (RotationInfo, info);
12978
12979       return;
12980     }
12981
12982   if (strcmp (name, "behaviours") == 0)
12983     {
12984       GSList *behaviours, *l;
12985
12986       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12987         return;
12988
12989       behaviours = g_value_get_pointer (value);
12990       for (l = behaviours; l != NULL; l = l->next)
12991         {
12992           ClutterBehaviour *behaviour = l->data;
12993
12994           clutter_behaviour_apply (behaviour, actor);
12995         }
12996
12997       g_slist_free (behaviours);
12998
12999       return;
13000     }
13001
13002   if (strcmp (name, "actions") == 0 ||
13003       strcmp (name, "constraints") == 0 ||
13004       strcmp (name, "effects") == 0)
13005     {
13006       GSList *metas, *l;
13007
13008       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13009         return;
13010
13011       metas = g_value_get_pointer (value);
13012       for (l = metas; l != NULL; l = l->next)
13013         {
13014           if (name[0] == 'a')
13015             clutter_actor_add_action (actor, l->data);
13016
13017           if (name[0] == 'c')
13018             clutter_actor_add_constraint (actor, l->data);
13019
13020           if (name[0] == 'e')
13021             clutter_actor_add_effect (actor, l->data);
13022         }
13023
13024       g_slist_free (metas);
13025
13026       return;
13027     }
13028
13029   g_object_set_property (G_OBJECT (scriptable), name, value);
13030 }
13031
13032 static void
13033 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13034 {
13035   iface->parse_custom_node = clutter_actor_parse_custom_node;
13036   iface->set_custom_property = clutter_actor_set_custom_property;
13037 }
13038
13039 static ClutterActorMeta *
13040 get_meta_from_animation_property (ClutterActor  *actor,
13041                                   const gchar   *name,
13042                                   gchar        **name_p)
13043 {
13044   ClutterActorPrivate *priv = actor->priv;
13045   ClutterActorMeta *meta = NULL;
13046   gchar **tokens;
13047
13048   /* if this is not a special property, fall through */
13049   if (name[0] != '@')
13050     return NULL;
13051
13052   /* detect the properties named using the following spec:
13053    *
13054    *   @<section>.<meta-name>.<property-name>
13055    *
13056    * where <section> can be one of the following:
13057    *
13058    *   - actions
13059    *   - constraints
13060    *   - effects
13061    *
13062    * and <meta-name> is the name set on a specific ActorMeta
13063    */
13064
13065   tokens = g_strsplit (name + 1, ".", -1);
13066   if (tokens == NULL || g_strv_length (tokens) != 3)
13067     {
13068       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13069                     name + 1);
13070       g_strfreev (tokens);
13071       return NULL;
13072     }
13073
13074   if (strcmp (tokens[0], "actions") == 0)
13075     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13076
13077   if (strcmp (tokens[0], "constraints") == 0)
13078     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13079
13080   if (strcmp (tokens[0], "effects") == 0)
13081     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13082
13083   if (name_p != NULL)
13084     *name_p = g_strdup (tokens[2]);
13085
13086   CLUTTER_NOTE (ANIMATION,
13087                 "Looking for property '%s' of object '%s' in section '%s'",
13088                 tokens[2],
13089                 tokens[1],
13090                 tokens[0]);
13091
13092   g_strfreev (tokens);
13093
13094   return meta;
13095 }
13096
13097 static GParamSpec *
13098 clutter_actor_find_property (ClutterAnimatable *animatable,
13099                              const gchar       *property_name)
13100 {
13101   ClutterActorMeta *meta = NULL;
13102   GObjectClass *klass = NULL;
13103   GParamSpec *pspec = NULL;
13104   gchar *p_name = NULL;
13105
13106   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13107                                            property_name,
13108                                            &p_name);
13109
13110   if (meta != NULL)
13111     {
13112       klass = G_OBJECT_GET_CLASS (meta);
13113
13114       pspec = g_object_class_find_property (klass, p_name);
13115     }
13116   else
13117     {
13118       klass = G_OBJECT_GET_CLASS (animatable);
13119
13120       pspec = g_object_class_find_property (klass, property_name);
13121     }
13122
13123   g_free (p_name);
13124
13125   return pspec;
13126 }
13127
13128 static void
13129 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13130                                  const gchar       *property_name,
13131                                  GValue            *initial)
13132 {
13133   ClutterActorMeta *meta = NULL;
13134   gchar *p_name = NULL;
13135
13136   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13137                                            property_name,
13138                                            &p_name);
13139
13140   if (meta != NULL)
13141     g_object_get_property (G_OBJECT (meta), p_name, initial);
13142   else
13143     g_object_get_property (G_OBJECT (animatable), property_name, initial);
13144
13145   g_free (p_name);
13146 }
13147
13148 /*
13149  * clutter_actor_set_animatable_property:
13150  * @actor: a #ClutterActor
13151  * @prop_id: the paramspec id
13152  * @value: the value to set
13153  * @pspec: the paramspec
13154  *
13155  * Sets values of animatable properties.
13156  *
13157  * This is a variant of clutter_actor_set_property() that gets called
13158  * by the #ClutterAnimatable implementation of #ClutterActor for the
13159  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13160  * #GParamSpec.
13161  *
13162  * Unlike the implementation of #GObjectClass.set_property(), this
13163  * function will not update the interval if a transition involving an
13164  * animatable property is in progress - this avoids cycles with the
13165  * transition API calling the public API.
13166  */
13167 static void
13168 clutter_actor_set_animatable_property (ClutterActor *actor,
13169                                        guint         prop_id,
13170                                        const GValue *value,
13171                                        GParamSpec   *pspec)
13172 {
13173   GObject *obj = G_OBJECT (actor);
13174
13175   g_object_freeze_notify (obj);
13176
13177   switch (prop_id)
13178     {
13179     case PROP_X:
13180       clutter_actor_set_x_internal (actor, g_value_get_float (value));
13181       break;
13182
13183     case PROP_Y:
13184       clutter_actor_set_y_internal (actor, g_value_get_float (value));
13185       break;
13186
13187     case PROP_POSITION:
13188       clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13189       break;
13190
13191     case PROP_WIDTH:
13192       clutter_actor_set_width_internal (actor, g_value_get_float (value));
13193       break;
13194
13195     case PROP_HEIGHT:
13196       clutter_actor_set_height_internal (actor, g_value_get_float (value));
13197       break;
13198
13199     case PROP_SIZE:
13200       clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13201       break;
13202
13203     case PROP_DEPTH:
13204       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13205       break;
13206
13207     case PROP_OPACITY:
13208       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13209       break;
13210
13211     case PROP_BACKGROUND_COLOR:
13212       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13213       break;
13214
13215     case PROP_SCALE_X:
13216       clutter_actor_set_scale_factor_internal (actor,
13217                                                g_value_get_double (value),
13218                                                pspec);
13219       break;
13220
13221     case PROP_SCALE_Y:
13222       clutter_actor_set_scale_factor_internal (actor,
13223                                                g_value_get_double (value),
13224                                                pspec);
13225       break;
13226
13227     case PROP_ROTATION_ANGLE_X:
13228       clutter_actor_set_rotation_angle_internal (actor,
13229                                                  CLUTTER_X_AXIS,
13230                                                  g_value_get_double (value));
13231       break;
13232
13233     case PROP_ROTATION_ANGLE_Y:
13234       clutter_actor_set_rotation_angle_internal (actor,
13235                                                  CLUTTER_Y_AXIS,
13236                                                  g_value_get_double (value));
13237       break;
13238
13239     case PROP_ROTATION_ANGLE_Z:
13240       clutter_actor_set_rotation_angle_internal (actor,
13241                                                  CLUTTER_Z_AXIS,
13242                                                  g_value_get_double (value));
13243       break;
13244
13245     case PROP_CONTENT_BOX:
13246       clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13247       break;
13248
13249     default:
13250       g_object_set_property (obj, pspec->name, value);
13251       break;
13252     }
13253
13254   g_object_thaw_notify (obj);
13255 }
13256
13257 static void
13258 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13259                                const gchar       *property_name,
13260                                const GValue      *final)
13261 {
13262   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13263   ClutterActorMeta *meta = NULL;
13264   gchar *p_name = NULL;
13265
13266   meta = get_meta_from_animation_property (actor,
13267                                            property_name,
13268                                            &p_name);
13269   if (meta != NULL)
13270     g_object_set_property (G_OBJECT (meta), p_name, final);
13271   else
13272     {
13273       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13274       GParamSpec *pspec;
13275
13276       pspec = g_object_class_find_property (obj_class, property_name);
13277
13278       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13279         {
13280           /* XXX - I'm going to the special hell for this */
13281           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13282         }
13283       else
13284         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13285     }
13286
13287   g_free (p_name);
13288 }
13289
13290 static void
13291 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13292 {
13293   iface->find_property = clutter_actor_find_property;
13294   iface->get_initial_state = clutter_actor_get_initial_state;
13295   iface->set_final_state = clutter_actor_set_final_state;
13296 }
13297
13298 /**
13299  * clutter_actor_transform_stage_point:
13300  * @self: A #ClutterActor
13301  * @x: (in): x screen coordinate of the point to unproject
13302  * @y: (in): y screen coordinate of the point to unproject
13303  * @x_out: (out): return location for the unprojected x coordinance
13304  * @y_out: (out): return location for the unprojected y coordinance
13305  *
13306  * This function translates screen coordinates (@x, @y) to
13307  * coordinates relative to the actor. For example, it can be used to translate
13308  * screen events from global screen coordinates into actor-local coordinates.
13309  *
13310  * The conversion can fail, notably if the transform stack results in the
13311  * actor being projected on the screen as a mere line.
13312  *
13313  * The conversion should not be expected to be pixel-perfect due to the
13314  * nature of the operation. In general the error grows when the skewing
13315  * of the actor rectangle on screen increases.
13316  *
13317  * <note><para>This function can be computationally intensive.</para></note>
13318  *
13319  * <note><para>This function only works when the allocation is up-to-date,
13320  * i.e. inside of paint().</para></note>
13321  *
13322  * Return value: %TRUE if conversion was successful.
13323  *
13324  * Since: 0.6
13325  */
13326 gboolean
13327 clutter_actor_transform_stage_point (ClutterActor *self,
13328                                      gfloat        x,
13329                                      gfloat        y,
13330                                      gfloat       *x_out,
13331                                      gfloat       *y_out)
13332 {
13333   ClutterVertex v[4];
13334   float ST[3][3];
13335   float RQ[3][3];
13336   int du, dv, xi, yi;
13337   float px, py;
13338   float xf, yf, wf, det;
13339   ClutterActorPrivate *priv;
13340
13341   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13342
13343   priv = self->priv;
13344
13345   /* This implementation is based on the quad -> quad projection algorithm
13346    * described by Paul Heckbert in:
13347    *
13348    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13349    *
13350    * and the sample implementation at:
13351    *
13352    *   http://www.cs.cmu.edu/~ph/src/texfund/
13353    *
13354    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13355    * quad to rectangle only, which significantly simplifies things; the
13356    * function calls have been unrolled, and most of the math is done in fixed
13357    * point.
13358    */
13359
13360   clutter_actor_get_abs_allocation_vertices (self, v);
13361
13362   /* Keeping these as ints simplifies the multiplication (no significant
13363    * loss of precision here).
13364    */
13365   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13366   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13367
13368   if (!du || !dv)
13369     return FALSE;
13370
13371 #define UX2FP(x)        (x)
13372 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13373
13374   /* First, find mapping from unit uv square to xy quadrilateral; this
13375    * equivalent to the pmap_square_quad() functions in the sample
13376    * implementation, which we can simplify, since our target is always
13377    * a rectangle.
13378    */
13379   px = v[0].x - v[1].x + v[3].x - v[2].x;
13380   py = v[0].y - v[1].y + v[3].y - v[2].y;
13381
13382   if (!px && !py)
13383     {
13384       /* affine transform */
13385       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13386       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13387       RQ[2][0] = UX2FP (v[0].x);
13388       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13389       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13390       RQ[2][1] = UX2FP (v[0].y);
13391       RQ[0][2] = 0;
13392       RQ[1][2] = 0;
13393       RQ[2][2] = 1.0;
13394     }
13395   else
13396     {
13397       /* projective transform */
13398       double dx1, dx2, dy1, dy2, del;
13399
13400       dx1 = UX2FP (v[1].x - v[3].x);
13401       dx2 = UX2FP (v[2].x - v[3].x);
13402       dy1 = UX2FP (v[1].y - v[3].y);
13403       dy2 = UX2FP (v[2].y - v[3].y);
13404
13405       del = DET2FP (dx1, dx2, dy1, dy2);
13406       if (!del)
13407         return FALSE;
13408
13409       /*
13410        * The division here needs to be done in floating point for
13411        * precisions reasons.
13412        */
13413       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13414       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13415       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13416       RQ[2][2] = 1.0;
13417       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13418       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13419       RQ[2][0] = UX2FP (v[0].x);
13420       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13421       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13422       RQ[2][1] = UX2FP (v[0].y);
13423     }
13424
13425   /*
13426    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13427    * square. Since our rectangle is based at 0,0 we only need to scale.
13428    */
13429   RQ[0][0] /= du;
13430   RQ[1][0] /= dv;
13431   RQ[0][1] /= du;
13432   RQ[1][1] /= dv;
13433   RQ[0][2] /= du;
13434   RQ[1][2] /= dv;
13435
13436   /*
13437    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13438    * inverse of that.
13439    */
13440   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13441   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13442   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13443   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13444   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13445   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13446   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13447   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13448   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13449
13450   /*
13451    * Check the resulting matrix is OK.
13452    */
13453   det = (RQ[0][0] * ST[0][0])
13454       + (RQ[0][1] * ST[0][1])
13455       + (RQ[0][2] * ST[0][2]);
13456   if (!det)
13457     return FALSE;
13458
13459   /*
13460    * Now transform our point with the ST matrix; the notional w
13461    * coordinate is 1, hence the last part is simply added.
13462    */
13463   xi = (int) x;
13464   yi = (int) y;
13465
13466   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13467   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13468   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13469
13470   if (x_out)
13471     *x_out = xf / wf;
13472
13473   if (y_out)
13474     *y_out = yf / wf;
13475
13476 #undef UX2FP
13477 #undef DET2FP
13478
13479   return TRUE;
13480 }
13481
13482 /**
13483  * clutter_actor_is_rotated:
13484  * @self: a #ClutterActor
13485  *
13486  * Checks whether any rotation is applied to the actor.
13487  *
13488  * Return value: %TRUE if the actor is rotated.
13489  *
13490  * Since: 0.6
13491  */
13492 gboolean
13493 clutter_actor_is_rotated (ClutterActor *self)
13494 {
13495   const ClutterTransformInfo *info;
13496
13497   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13498
13499   info = _clutter_actor_get_transform_info_or_defaults (self);
13500
13501   if (info->rx_angle || info->ry_angle || info->rz_angle)
13502     return TRUE;
13503
13504   return FALSE;
13505 }
13506
13507 /**
13508  * clutter_actor_is_scaled:
13509  * @self: a #ClutterActor
13510  *
13511  * Checks whether the actor is scaled in either dimension.
13512  *
13513  * Return value: %TRUE if the actor is scaled.
13514  *
13515  * Since: 0.6
13516  */
13517 gboolean
13518 clutter_actor_is_scaled (ClutterActor *self)
13519 {
13520   const ClutterTransformInfo *info;
13521
13522   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13523
13524   info = _clutter_actor_get_transform_info_or_defaults (self);
13525
13526   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13527     return TRUE;
13528
13529   return FALSE;
13530 }
13531
13532 ClutterActor *
13533 _clutter_actor_get_stage_internal (ClutterActor *actor)
13534 {
13535   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13536     actor = actor->priv->parent;
13537
13538   return actor;
13539 }
13540
13541 /**
13542  * clutter_actor_get_stage:
13543  * @actor: a #ClutterActor
13544  *
13545  * Retrieves the #ClutterStage where @actor is contained.
13546  *
13547  * Return value: (transfer none) (type Clutter.Stage): the stage
13548  *   containing the actor, or %NULL
13549  *
13550  * Since: 0.8
13551  */
13552 ClutterActor *
13553 clutter_actor_get_stage (ClutterActor *actor)
13554 {
13555   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13556
13557   return _clutter_actor_get_stage_internal (actor);
13558 }
13559
13560 /**
13561  * clutter_actor_allocate_available_size:
13562  * @self: a #ClutterActor
13563  * @x: the actor's X coordinate
13564  * @y: the actor's Y coordinate
13565  * @available_width: the maximum available width, or -1 to use the
13566  *   actor's natural width
13567  * @available_height: the maximum available height, or -1 to use the
13568  *   actor's natural height
13569  * @flags: flags controlling the allocation
13570  *
13571  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13572  * preferred size, but limiting it to the maximum available width
13573  * and height provided.
13574  *
13575  * This function will do the right thing when dealing with the
13576  * actor's request mode.
13577  *
13578  * The implementation of this function is equivalent to:
13579  *
13580  * |[
13581  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13582  *     {
13583  *       clutter_actor_get_preferred_width (self, available_height,
13584  *                                          &amp;min_width,
13585  *                                          &amp;natural_width);
13586  *       width = CLAMP (natural_width, min_width, available_width);
13587  *
13588  *       clutter_actor_get_preferred_height (self, width,
13589  *                                           &amp;min_height,
13590  *                                           &amp;natural_height);
13591  *       height = CLAMP (natural_height, min_height, available_height);
13592  *     }
13593  *   else
13594  *     {
13595  *       clutter_actor_get_preferred_height (self, available_width,
13596  *                                           &amp;min_height,
13597  *                                           &amp;natural_height);
13598  *       height = CLAMP (natural_height, min_height, available_height);
13599  *
13600  *       clutter_actor_get_preferred_width (self, height,
13601  *                                          &amp;min_width,
13602  *                                          &amp;natural_width);
13603  *       width = CLAMP (natural_width, min_width, available_width);
13604  *     }
13605  *
13606  *   box.x1 = x; box.y1 = y;
13607  *   box.x2 = box.x1 + available_width;
13608  *   box.y2 = box.y1 + available_height;
13609  *   clutter_actor_allocate (self, &amp;box, flags);
13610  * ]|
13611  *
13612  * This function can be used by fluid layout managers to allocate
13613  * an actor's preferred size without making it bigger than the area
13614  * available for the container.
13615  *
13616  * Since: 1.0
13617  */
13618 void
13619 clutter_actor_allocate_available_size (ClutterActor           *self,
13620                                        gfloat                  x,
13621                                        gfloat                  y,
13622                                        gfloat                  available_width,
13623                                        gfloat                  available_height,
13624                                        ClutterAllocationFlags  flags)
13625 {
13626   ClutterActorPrivate *priv;
13627   gfloat width, height;
13628   gfloat min_width, min_height;
13629   gfloat natural_width, natural_height;
13630   ClutterActorBox box;
13631
13632   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13633
13634   priv = self->priv;
13635
13636   width = height = 0.0;
13637
13638   switch (priv->request_mode)
13639     {
13640     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13641       clutter_actor_get_preferred_width (self, available_height,
13642                                          &min_width,
13643                                          &natural_width);
13644       width  = CLAMP (natural_width, min_width, available_width);
13645
13646       clutter_actor_get_preferred_height (self, width,
13647                                           &min_height,
13648                                           &natural_height);
13649       height = CLAMP (natural_height, min_height, available_height);
13650       break;
13651
13652     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13653       clutter_actor_get_preferred_height (self, available_width,
13654                                           &min_height,
13655                                           &natural_height);
13656       height = CLAMP (natural_height, min_height, available_height);
13657
13658       clutter_actor_get_preferred_width (self, height,
13659                                          &min_width,
13660                                          &natural_width);
13661       width  = CLAMP (natural_width, min_width, available_width);
13662       break;
13663     }
13664
13665
13666   box.x1 = x;
13667   box.y1 = y;
13668   box.x2 = box.x1 + width;
13669   box.y2 = box.y1 + height;
13670   clutter_actor_allocate (self, &box, flags);
13671 }
13672
13673 /**
13674  * clutter_actor_allocate_preferred_size:
13675  * @self: a #ClutterActor
13676  * @flags: flags controlling the allocation
13677  *
13678  * Allocates the natural size of @self.
13679  *
13680  * This function is a utility call for #ClutterActor implementations
13681  * that allocates the actor's preferred natural size. It can be used
13682  * by fixed layout managers (like #ClutterGroup or so called
13683  * 'composite actors') inside the ClutterActor::allocate
13684  * implementation to give each child exactly how much space it
13685  * requires.
13686  *
13687  * This function is not meant to be used by applications. It is also
13688  * not meant to be used outside the implementation of the
13689  * ClutterActor::allocate virtual function.
13690  *
13691  * Since: 0.8
13692  */
13693 void
13694 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13695                                        ClutterAllocationFlags  flags)
13696 {
13697   gfloat actor_x, actor_y;
13698   gfloat natural_width, natural_height;
13699   ClutterActorBox actor_box;
13700
13701   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13702
13703   actor_x = clutter_actor_get_x (self);
13704   actor_y = clutter_actor_get_y (self);
13705
13706   clutter_actor_get_preferred_size (self,
13707                                     NULL, NULL,
13708                                     &natural_width,
13709                                     &natural_height);
13710
13711   actor_box.x1 = actor_x;
13712   actor_box.y1 = actor_y;
13713   actor_box.x2 = actor_box.x1 + natural_width;
13714   actor_box.y2 = actor_box.y1 + natural_height;
13715
13716   clutter_actor_allocate (self, &actor_box, flags);
13717 }
13718
13719 /**
13720  * clutter_actor_allocate_align_fill:
13721  * @self: a #ClutterActor
13722  * @box: a #ClutterActorBox, containing the available width and height
13723  * @x_align: the horizontal alignment, between 0 and 1
13724  * @y_align: the vertical alignment, between 0 and 1
13725  * @x_fill: whether the actor should fill horizontally
13726  * @y_fill: whether the actor should fill vertically
13727  * @flags: allocation flags to be passed to clutter_actor_allocate()
13728  *
13729  * Allocates @self by taking into consideration the available allocation
13730  * area; an alignment factor on either axis; and whether the actor should
13731  * fill the allocation on either axis.
13732  *
13733  * The @box should contain the available allocation width and height;
13734  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13735  * allocation will be offset by their value.
13736  *
13737  * This function takes into consideration the geometry request specified by
13738  * the #ClutterActor:request-mode property, and the text direction.
13739  *
13740  * This function is useful for fluid layout managers, like #ClutterBinLayout
13741  * or #ClutterTableLayout
13742  *
13743  * Since: 1.4
13744  */
13745 void
13746 clutter_actor_allocate_align_fill (ClutterActor           *self,
13747                                    const ClutterActorBox  *box,
13748                                    gdouble                 x_align,
13749                                    gdouble                 y_align,
13750                                    gboolean                x_fill,
13751                                    gboolean                y_fill,
13752                                    ClutterAllocationFlags  flags)
13753 {
13754   ClutterActorPrivate *priv;
13755   ClutterActorBox allocation = { 0, };
13756   gfloat x_offset, y_offset;
13757   gfloat available_width, available_height;
13758   gfloat child_width, child_height;
13759
13760   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13761   g_return_if_fail (box != NULL);
13762   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13763   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13764
13765   priv = self->priv;
13766
13767   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13768   clutter_actor_box_get_size (box, &available_width, &available_height);
13769
13770   if (available_width < 0)
13771     available_width = 0;
13772
13773   if (available_height < 0)
13774     available_height = 0;
13775
13776   if (x_fill)
13777     {
13778       allocation.x1 = x_offset;
13779       allocation.x2 = allocation.x1 + available_width;
13780     }
13781
13782   if (y_fill)
13783     {
13784       allocation.y1 = y_offset;
13785       allocation.y2 = allocation.y1 + available_height;
13786     }
13787
13788   /* if we are filling horizontally and vertically then we're done */
13789   if (x_fill && y_fill)
13790     goto out;
13791
13792   child_width = child_height = 0.0f;
13793
13794   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13795     {
13796       gfloat min_width, natural_width;
13797       gfloat min_height, natural_height;
13798
13799       clutter_actor_get_preferred_width (self, available_height,
13800                                          &min_width,
13801                                          &natural_width);
13802
13803       child_width = CLAMP (natural_width, min_width, available_width);
13804
13805       if (!y_fill)
13806         {
13807           clutter_actor_get_preferred_height (self, child_width,
13808                                               &min_height,
13809                                               &natural_height);
13810
13811           child_height = CLAMP (natural_height, min_height, available_height);
13812         }
13813     }
13814   else
13815     {
13816       gfloat min_width, natural_width;
13817       gfloat min_height, natural_height;
13818
13819       clutter_actor_get_preferred_height (self, available_width,
13820                                           &min_height,
13821                                           &natural_height);
13822
13823       child_height = CLAMP (natural_height, min_height, available_height);
13824
13825       if (!x_fill)
13826         {
13827           clutter_actor_get_preferred_width (self, child_height,
13828                                              &min_width,
13829                                              &natural_width);
13830
13831           child_width = CLAMP (natural_width, min_width, available_width);
13832         }
13833     }
13834
13835   /* invert the horizontal alignment for RTL languages */
13836   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13837     x_align = 1.0 - x_align;
13838
13839   if (!x_fill)
13840     {
13841       allocation.x1 = x_offset
13842                     + ((available_width - child_width) * x_align);
13843       allocation.x2 = allocation.x1 + child_width;
13844     }
13845
13846   if (!y_fill)
13847     {
13848       allocation.y1 = y_offset
13849                     + ((available_height - child_height) * y_align);
13850       allocation.y2 = allocation.y1 + child_height;
13851     }
13852
13853 out:
13854   clutter_actor_box_clamp_to_pixel (&allocation);
13855   clutter_actor_allocate (self, &allocation, flags);
13856 }
13857
13858 /**
13859  * clutter_actor_grab_key_focus:
13860  * @self: a #ClutterActor
13861  *
13862  * Sets the key focus of the #ClutterStage including @self
13863  * to this #ClutterActor.
13864  *
13865  * Since: 1.0
13866  */
13867 void
13868 clutter_actor_grab_key_focus (ClutterActor *self)
13869 {
13870   ClutterActor *stage;
13871
13872   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13873
13874   stage = _clutter_actor_get_stage_internal (self);
13875   if (stage != NULL)
13876     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13877 }
13878
13879 /**
13880  * clutter_actor_get_pango_context:
13881  * @self: a #ClutterActor
13882  *
13883  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13884  * is already configured using the appropriate font map, resolution
13885  * and font options.
13886  *
13887  * Unlike clutter_actor_create_pango_context(), this context is owend
13888  * by the #ClutterActor and it will be updated each time the options
13889  * stored by the #ClutterBackend change.
13890  *
13891  * You can use the returned #PangoContext to create a #PangoLayout
13892  * and render text using cogl_pango_render_layout() to reuse the
13893  * glyphs cache also used by Clutter.
13894  *
13895  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13896  *   The returned #PangoContext is owned by the actor and should not be
13897  *   unreferenced by the application code
13898  *
13899  * Since: 1.0
13900  */
13901 PangoContext *
13902 clutter_actor_get_pango_context (ClutterActor *self)
13903 {
13904   ClutterActorPrivate *priv;
13905
13906   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13907
13908   priv = self->priv;
13909
13910   if (priv->pango_context != NULL)
13911     return priv->pango_context;
13912
13913   priv->pango_context = _clutter_context_get_pango_context ();
13914   g_object_ref (priv->pango_context);
13915
13916   return priv->pango_context;
13917 }
13918
13919 /**
13920  * clutter_actor_create_pango_context:
13921  * @self: a #ClutterActor
13922  *
13923  * Creates a #PangoContext for the given actor. The #PangoContext
13924  * is already configured using the appropriate font map, resolution
13925  * and font options.
13926  *
13927  * See also clutter_actor_get_pango_context().
13928  *
13929  * Return value: (transfer full): the newly created #PangoContext.
13930  *   Use g_object_unref() on the returned value to deallocate its
13931  *   resources
13932  *
13933  * Since: 1.0
13934  */
13935 PangoContext *
13936 clutter_actor_create_pango_context (ClutterActor *self)
13937 {
13938   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13939
13940   return _clutter_context_create_pango_context ();
13941 }
13942
13943 /**
13944  * clutter_actor_create_pango_layout:
13945  * @self: a #ClutterActor
13946  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13947  *
13948  * Creates a new #PangoLayout from the same #PangoContext used
13949  * by the #ClutterActor. The #PangoLayout is already configured
13950  * with the font map, resolution and font options, and the
13951  * given @text.
13952  *
13953  * If you want to keep around a #PangoLayout created by this
13954  * function you will have to connect to the #ClutterBackend::font-changed
13955  * and #ClutterBackend::resolution-changed signals, and call
13956  * pango_layout_context_changed() in response to them.
13957  *
13958  * Return value: (transfer full): the newly created #PangoLayout.
13959  *   Use g_object_unref() when done
13960  *
13961  * Since: 1.0
13962  */
13963 PangoLayout *
13964 clutter_actor_create_pango_layout (ClutterActor *self,
13965                                    const gchar  *text)
13966 {
13967   PangoContext *context;
13968   PangoLayout *layout;
13969
13970   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13971
13972   context = clutter_actor_get_pango_context (self);
13973   layout = pango_layout_new (context);
13974
13975   if (text)
13976     pango_layout_set_text (layout, text, -1);
13977
13978   return layout;
13979 }
13980
13981 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13982  * ClutterOffscreenEffect.
13983  */
13984 void
13985 _clutter_actor_set_opacity_override (ClutterActor *self,
13986                                      gint          opacity)
13987 {
13988   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13989
13990   self->priv->opacity_override = opacity;
13991 }
13992
13993 gint
13994 _clutter_actor_get_opacity_override (ClutterActor *self)
13995 {
13996   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13997
13998   return self->priv->opacity_override;
13999 }
14000
14001 /* Allows you to disable applying the actors model view transform during
14002  * a paint. Used by ClutterClone. */
14003 void
14004 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14005                                                 gboolean      enable)
14006 {
14007   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14008
14009   self->priv->enable_model_view_transform = enable;
14010 }
14011
14012 void
14013 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14014                                           gboolean      enable)
14015 {
14016   ClutterActorPrivate *priv;
14017
14018   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14019
14020   priv = self->priv;
14021
14022   priv->enable_paint_unmapped = enable;
14023
14024   if (priv->enable_paint_unmapped)
14025     {
14026       /* Make sure that the parents of the widget are realized first;
14027        * otherwise checks in clutter_actor_update_map_state() will
14028        * fail.
14029        */
14030       clutter_actor_realize (self);
14031
14032       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14033     }
14034   else
14035     {
14036       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14037     }
14038 }
14039
14040 static void
14041 clutter_anchor_coord_get_units (ClutterActor      *self,
14042                                 const AnchorCoord *coord,
14043                                 gfloat            *x,
14044                                 gfloat            *y,
14045                                 gfloat            *z)
14046 {
14047   if (coord->is_fractional)
14048     {
14049       gfloat actor_width, actor_height;
14050
14051       clutter_actor_get_size (self, &actor_width, &actor_height);
14052
14053       if (x)
14054         *x = actor_width * coord->v.fraction.x;
14055
14056       if (y)
14057         *y = actor_height * coord->v.fraction.y;
14058
14059       if (z)
14060         *z = 0;
14061     }
14062   else
14063     {
14064       if (x)
14065         *x = coord->v.units.x;
14066
14067       if (y)
14068         *y = coord->v.units.y;
14069
14070       if (z)
14071         *z = coord->v.units.z;
14072     }
14073 }
14074
14075 static void
14076 clutter_anchor_coord_set_units (AnchorCoord *coord,
14077                                 gfloat       x,
14078                                 gfloat       y,
14079                                 gfloat       z)
14080 {
14081   coord->is_fractional = FALSE;
14082   coord->v.units.x = x;
14083   coord->v.units.y = y;
14084   coord->v.units.z = z;
14085 }
14086
14087 static ClutterGravity
14088 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14089 {
14090   if (coord->is_fractional)
14091     {
14092       if (coord->v.fraction.x == 0.0)
14093         {
14094           if (coord->v.fraction.y == 0.0)
14095             return CLUTTER_GRAVITY_NORTH_WEST;
14096           else if (coord->v.fraction.y == 0.5)
14097             return CLUTTER_GRAVITY_WEST;
14098           else if (coord->v.fraction.y == 1.0)
14099             return CLUTTER_GRAVITY_SOUTH_WEST;
14100           else
14101             return CLUTTER_GRAVITY_NONE;
14102         }
14103       else if (coord->v.fraction.x == 0.5)
14104         {
14105           if (coord->v.fraction.y == 0.0)
14106             return CLUTTER_GRAVITY_NORTH;
14107           else if (coord->v.fraction.y == 0.5)
14108             return CLUTTER_GRAVITY_CENTER;
14109           else if (coord->v.fraction.y == 1.0)
14110             return CLUTTER_GRAVITY_SOUTH;
14111           else
14112             return CLUTTER_GRAVITY_NONE;
14113         }
14114       else if (coord->v.fraction.x == 1.0)
14115         {
14116           if (coord->v.fraction.y == 0.0)
14117             return CLUTTER_GRAVITY_NORTH_EAST;
14118           else if (coord->v.fraction.y == 0.5)
14119             return CLUTTER_GRAVITY_EAST;
14120           else if (coord->v.fraction.y == 1.0)
14121             return CLUTTER_GRAVITY_SOUTH_EAST;
14122           else
14123             return CLUTTER_GRAVITY_NONE;
14124         }
14125       else
14126         return CLUTTER_GRAVITY_NONE;
14127     }
14128   else
14129     return CLUTTER_GRAVITY_NONE;
14130 }
14131
14132 static void
14133 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14134                                   ClutterGravity  gravity)
14135 {
14136   switch (gravity)
14137     {
14138     case CLUTTER_GRAVITY_NORTH:
14139       coord->v.fraction.x = 0.5;
14140       coord->v.fraction.y = 0.0;
14141       break;
14142
14143     case CLUTTER_GRAVITY_NORTH_EAST:
14144       coord->v.fraction.x = 1.0;
14145       coord->v.fraction.y = 0.0;
14146       break;
14147
14148     case CLUTTER_GRAVITY_EAST:
14149       coord->v.fraction.x = 1.0;
14150       coord->v.fraction.y = 0.5;
14151       break;
14152
14153     case CLUTTER_GRAVITY_SOUTH_EAST:
14154       coord->v.fraction.x = 1.0;
14155       coord->v.fraction.y = 1.0;
14156       break;
14157
14158     case CLUTTER_GRAVITY_SOUTH:
14159       coord->v.fraction.x = 0.5;
14160       coord->v.fraction.y = 1.0;
14161       break;
14162
14163     case CLUTTER_GRAVITY_SOUTH_WEST:
14164       coord->v.fraction.x = 0.0;
14165       coord->v.fraction.y = 1.0;
14166       break;
14167
14168     case CLUTTER_GRAVITY_WEST:
14169       coord->v.fraction.x = 0.0;
14170       coord->v.fraction.y = 0.5;
14171       break;
14172
14173     case CLUTTER_GRAVITY_NORTH_WEST:
14174       coord->v.fraction.x = 0.0;
14175       coord->v.fraction.y = 0.0;
14176       break;
14177
14178     case CLUTTER_GRAVITY_CENTER:
14179       coord->v.fraction.x = 0.5;
14180       coord->v.fraction.y = 0.5;
14181       break;
14182
14183     default:
14184       coord->v.fraction.x = 0.0;
14185       coord->v.fraction.y = 0.0;
14186       break;
14187     }
14188
14189   coord->is_fractional = TRUE;
14190 }
14191
14192 static gboolean
14193 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14194 {
14195   if (coord->is_fractional)
14196     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14197   else
14198     return (coord->v.units.x == 0.0
14199             && coord->v.units.y == 0.0
14200             && coord->v.units.z == 0.0);
14201 }
14202
14203 /**
14204  * clutter_actor_get_flags:
14205  * @self: a #ClutterActor
14206  *
14207  * Retrieves the flags set on @self
14208  *
14209  * Return value: a bitwise or of #ClutterActorFlags or 0
14210  *
14211  * Since: 1.0
14212  */
14213 ClutterActorFlags
14214 clutter_actor_get_flags (ClutterActor *self)
14215 {
14216   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14217
14218   return self->flags;
14219 }
14220
14221 /**
14222  * clutter_actor_set_flags:
14223  * @self: a #ClutterActor
14224  * @flags: the flags to set
14225  *
14226  * Sets @flags on @self
14227  *
14228  * This function will emit notifications for the changed properties
14229  *
14230  * Since: 1.0
14231  */
14232 void
14233 clutter_actor_set_flags (ClutterActor      *self,
14234                          ClutterActorFlags  flags)
14235 {
14236   ClutterActorFlags old_flags;
14237   GObject *obj;
14238   gboolean was_reactive_set, reactive_set;
14239   gboolean was_realized_set, realized_set;
14240   gboolean was_mapped_set, mapped_set;
14241   gboolean was_visible_set, visible_set;
14242
14243   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14244
14245   if (self->flags == flags)
14246     return;
14247
14248   obj = G_OBJECT (self);
14249   g_object_ref (obj);
14250   g_object_freeze_notify (obj);
14251
14252   old_flags = self->flags;
14253
14254   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14255   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14256   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14257   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14258
14259   self->flags |= flags;
14260
14261   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14262   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14263   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14264   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14265
14266   if (reactive_set != was_reactive_set)
14267     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14268
14269   if (realized_set != was_realized_set)
14270     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14271
14272   if (mapped_set != was_mapped_set)
14273     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14274
14275   if (visible_set != was_visible_set)
14276     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14277
14278   g_object_thaw_notify (obj);
14279   g_object_unref (obj);
14280 }
14281
14282 /**
14283  * clutter_actor_unset_flags:
14284  * @self: a #ClutterActor
14285  * @flags: the flags to unset
14286  *
14287  * Unsets @flags on @self
14288  *
14289  * This function will emit notifications for the changed properties
14290  *
14291  * Since: 1.0
14292  */
14293 void
14294 clutter_actor_unset_flags (ClutterActor      *self,
14295                            ClutterActorFlags  flags)
14296 {
14297   ClutterActorFlags old_flags;
14298   GObject *obj;
14299   gboolean was_reactive_set, reactive_set;
14300   gboolean was_realized_set, realized_set;
14301   gboolean was_mapped_set, mapped_set;
14302   gboolean was_visible_set, visible_set;
14303
14304   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14305
14306   obj = G_OBJECT (self);
14307   g_object_freeze_notify (obj);
14308
14309   old_flags = self->flags;
14310
14311   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14312   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14313   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14314   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14315
14316   self->flags &= ~flags;
14317
14318   if (self->flags == old_flags)
14319     return;
14320
14321   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14322   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14323   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14324   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14325
14326   if (reactive_set != was_reactive_set)
14327     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14328
14329   if (realized_set != was_realized_set)
14330     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14331
14332   if (mapped_set != was_mapped_set)
14333     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14334
14335   if (visible_set != was_visible_set)
14336     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14337
14338   g_object_thaw_notify (obj);
14339 }
14340
14341 /**
14342  * clutter_actor_get_transformation_matrix:
14343  * @self: a #ClutterActor
14344  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14345  *
14346  * Retrieves the transformations applied to @self relative to its
14347  * parent.
14348  *
14349  * Since: 1.0
14350  */
14351 void
14352 clutter_actor_get_transformation_matrix (ClutterActor *self,
14353                                          CoglMatrix   *matrix)
14354 {
14355   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14356
14357   cogl_matrix_init_identity (matrix);
14358
14359   _clutter_actor_apply_modelview_transform (self, matrix);
14360 }
14361
14362 void
14363 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14364                                    gboolean      is_in_clone_paint)
14365 {
14366   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14367   self->priv->in_clone_paint = is_in_clone_paint;
14368 }
14369
14370 /**
14371  * clutter_actor_is_in_clone_paint:
14372  * @self: a #ClutterActor
14373  *
14374  * Checks whether @self is being currently painted by a #ClutterClone
14375  *
14376  * This function is useful only inside the ::paint virtual function
14377  * implementations or within handlers for the #ClutterActor::paint
14378  * signal
14379  *
14380  * This function should not be used by applications
14381  *
14382  * Return value: %TRUE if the #ClutterActor is currently being painted
14383  *   by a #ClutterClone, and %FALSE otherwise
14384  *
14385  * Since: 1.0
14386  */
14387 gboolean
14388 clutter_actor_is_in_clone_paint (ClutterActor *self)
14389 {
14390   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14391
14392   return self->priv->in_clone_paint;
14393 }
14394
14395 static gboolean
14396 set_direction_recursive (ClutterActor *actor,
14397                          gpointer      user_data)
14398 {
14399   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14400
14401   clutter_actor_set_text_direction (actor, text_dir);
14402
14403   return TRUE;
14404 }
14405
14406 /**
14407  * clutter_actor_set_text_direction:
14408  * @self: a #ClutterActor
14409  * @text_dir: the text direction for @self
14410  *
14411  * Sets the #ClutterTextDirection for an actor
14412  *
14413  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14414  *
14415  * If @self implements #ClutterContainer then this function will recurse
14416  * inside all the children of @self (including the internal ones).
14417  *
14418  * Composite actors not implementing #ClutterContainer, or actors requiring
14419  * special handling when the text direction changes, should connect to
14420  * the #GObject::notify signal for the #ClutterActor:text-direction property
14421  *
14422  * Since: 1.2
14423  */
14424 void
14425 clutter_actor_set_text_direction (ClutterActor         *self,
14426                                   ClutterTextDirection  text_dir)
14427 {
14428   ClutterActorPrivate *priv;
14429
14430   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14431   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14432
14433   priv = self->priv;
14434
14435   if (priv->text_direction != text_dir)
14436     {
14437       priv->text_direction = text_dir;
14438
14439       /* we need to emit the notify::text-direction first, so that
14440        * the sub-classes can catch that and do specific handling of
14441        * the text direction; see clutter_text_direction_changed_cb()
14442        * inside clutter-text.c
14443        */
14444       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14445
14446       _clutter_actor_foreach_child (self, set_direction_recursive,
14447                                     GINT_TO_POINTER (text_dir));
14448
14449       clutter_actor_queue_relayout (self);
14450     }
14451 }
14452
14453 void
14454 _clutter_actor_set_has_pointer (ClutterActor *self,
14455                                 gboolean      has_pointer)
14456 {
14457   ClutterActorPrivate *priv = self->priv;
14458
14459   if (priv->has_pointer != has_pointer)
14460     {
14461       priv->has_pointer = has_pointer;
14462
14463       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14464     }
14465 }
14466
14467 /**
14468  * clutter_actor_get_text_direction:
14469  * @self: a #ClutterActor
14470  *
14471  * Retrieves the value set using clutter_actor_set_text_direction()
14472  *
14473  * If no text direction has been previously set, the default text
14474  * direction, as returned by clutter_get_default_text_direction(), will
14475  * be returned instead
14476  *
14477  * Return value: the #ClutterTextDirection for the actor
14478  *
14479  * Since: 1.2
14480  */
14481 ClutterTextDirection
14482 clutter_actor_get_text_direction (ClutterActor *self)
14483 {
14484   ClutterActorPrivate *priv;
14485
14486   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14487                         CLUTTER_TEXT_DIRECTION_LTR);
14488
14489   priv = self->priv;
14490
14491   /* if no direction has been set yet use the default */
14492   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14493     priv->text_direction = clutter_get_default_text_direction ();
14494
14495   return priv->text_direction;
14496 }
14497
14498 /**
14499  * clutter_actor_push_internal:
14500  * @self: a #ClutterActor
14501  *
14502  * Should be used by actors implementing the #ClutterContainer and with
14503  * internal children added through clutter_actor_set_parent(), for instance:
14504  *
14505  * |[
14506  *   static void
14507  *   my_actor_init (MyActor *self)
14508  *   {
14509  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14510  *
14511  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14512  *
14513  *     /&ast; calling clutter_actor_set_parent() now will result in
14514  *      &ast; the internal flag being set on a child of MyActor
14515  *      &ast;/
14516  *
14517  *     /&ast; internal child - a background texture &ast;/
14518  *     self->priv->background_tex = clutter_texture_new ();
14519  *     clutter_actor_set_parent (self->priv->background_tex,
14520  *                               CLUTTER_ACTOR (self));
14521  *
14522  *     /&ast; internal child - a label &ast;/
14523  *     self->priv->label = clutter_text_new ();
14524  *     clutter_actor_set_parent (self->priv->label,
14525  *                               CLUTTER_ACTOR (self));
14526  *
14527  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14528  *
14529  *     /&ast; calling clutter_actor_set_parent() now will not result in
14530  *      &ast; the internal flag being set on a child of MyActor
14531  *      &ast;/
14532  *   }
14533  * ]|
14534  *
14535  * This function will be used by Clutter to toggle an "internal child"
14536  * flag whenever clutter_actor_set_parent() is called; internal children
14537  * are handled differently by Clutter, specifically when destroying their
14538  * parent.
14539  *
14540  * Call clutter_actor_pop_internal() when you finished adding internal
14541  * children.
14542  *
14543  * Nested calls to clutter_actor_push_internal() are allowed, but each
14544  * one must by followed by a clutter_actor_pop_internal() call.
14545  *
14546  * Since: 1.2
14547  *
14548  * Deprecated: 1.10: All children of an actor are accessible through
14549  *   the #ClutterActor API, and #ClutterActor implements the
14550  *   #ClutterContainer interface, so this function is only useful
14551  *   for legacy containers overriding the default implementation.
14552  */
14553 void
14554 clutter_actor_push_internal (ClutterActor *self)
14555 {
14556   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14557
14558   self->priv->internal_child += 1;
14559 }
14560
14561 /**
14562  * clutter_actor_pop_internal:
14563  * @self: a #ClutterActor
14564  *
14565  * Disables the effects of clutter_actor_push_internal().
14566  *
14567  * Since: 1.2
14568  *
14569  * Deprecated: 1.10: All children of an actor are accessible through
14570  *   the #ClutterActor API. This function is only useful for legacy
14571  *   containers overriding the default implementation of the
14572  *   #ClutterContainer interface.
14573  */
14574 void
14575 clutter_actor_pop_internal (ClutterActor *self)
14576 {
14577   ClutterActorPrivate *priv;
14578
14579   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14580
14581   priv = self->priv;
14582
14583   if (priv->internal_child == 0)
14584     {
14585       g_warning ("Mismatched %s: you need to call "
14586                  "clutter_actor_push_composite() at least once before "
14587                  "calling this function", G_STRFUNC);
14588       return;
14589     }
14590
14591   priv->internal_child -= 1;
14592 }
14593
14594 /**
14595  * clutter_actor_has_pointer:
14596  * @self: a #ClutterActor
14597  *
14598  * Checks whether an actor contains the pointer of a
14599  * #ClutterInputDevice
14600  *
14601  * Return value: %TRUE if the actor contains the pointer, and
14602  *   %FALSE otherwise
14603  *
14604  * Since: 1.2
14605  */
14606 gboolean
14607 clutter_actor_has_pointer (ClutterActor *self)
14608 {
14609   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14610
14611   return self->priv->has_pointer;
14612 }
14613
14614 /* XXX: This is a workaround for not being able to break the ABI of
14615  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14616  * clutter_actor_queue_clipped_redraw() for details.
14617  */
14618 ClutterPaintVolume *
14619 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14620 {
14621   return g_object_get_data (G_OBJECT (self),
14622                             "-clutter-actor-queue-redraw-clip");
14623 }
14624
14625 void
14626 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14627                                       ClutterPaintVolume *clip)
14628 {
14629   g_object_set_data (G_OBJECT (self),
14630                      "-clutter-actor-queue-redraw-clip",
14631                      clip);
14632 }
14633
14634 /**
14635  * clutter_actor_has_allocation:
14636  * @self: a #ClutterActor
14637  *
14638  * Checks if the actor has an up-to-date allocation assigned to
14639  * it. This means that the actor should have an allocation: it's
14640  * visible and has a parent. It also means that there is no
14641  * outstanding relayout request in progress for the actor or its
14642  * children (There might be other outstanding layout requests in
14643  * progress that will cause the actor to get a new allocation
14644  * when the stage is laid out, however).
14645  *
14646  * If this function returns %FALSE, then the actor will normally
14647  * be allocated before it is next drawn on the screen.
14648  *
14649  * Return value: %TRUE if the actor has an up-to-date allocation
14650  *
14651  * Since: 1.4
14652  */
14653 gboolean
14654 clutter_actor_has_allocation (ClutterActor *self)
14655 {
14656   ClutterActorPrivate *priv;
14657
14658   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14659
14660   priv = self->priv;
14661
14662   return priv->parent != NULL &&
14663          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14664          !priv->needs_allocation;
14665 }
14666
14667 /**
14668  * clutter_actor_add_action:
14669  * @self: a #ClutterActor
14670  * @action: a #ClutterAction
14671  *
14672  * Adds @action to the list of actions applied to @self
14673  *
14674  * A #ClutterAction can only belong to one actor at a time
14675  *
14676  * The #ClutterActor will hold a reference on @action until either
14677  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14678  * is called
14679  *
14680  * Since: 1.4
14681  */
14682 void
14683 clutter_actor_add_action (ClutterActor  *self,
14684                           ClutterAction *action)
14685 {
14686   ClutterActorPrivate *priv;
14687
14688   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14689   g_return_if_fail (CLUTTER_IS_ACTION (action));
14690
14691   priv = self->priv;
14692
14693   if (priv->actions == NULL)
14694     {
14695       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14696       priv->actions->actor = self;
14697     }
14698
14699   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14700
14701   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14702 }
14703
14704 /**
14705  * clutter_actor_add_action_with_name:
14706  * @self: a #ClutterActor
14707  * @name: the name to set on the action
14708  * @action: a #ClutterAction
14709  *
14710  * A convenience function for setting the name of a #ClutterAction
14711  * while adding it to the list of actions applied to @self
14712  *
14713  * This function is the logical equivalent of:
14714  *
14715  * |[
14716  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14717  *   clutter_actor_add_action (self, action);
14718  * ]|
14719  *
14720  * Since: 1.4
14721  */
14722 void
14723 clutter_actor_add_action_with_name (ClutterActor  *self,
14724                                     const gchar   *name,
14725                                     ClutterAction *action)
14726 {
14727   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14728   g_return_if_fail (name != NULL);
14729   g_return_if_fail (CLUTTER_IS_ACTION (action));
14730
14731   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14732   clutter_actor_add_action (self, action);
14733 }
14734
14735 /**
14736  * clutter_actor_remove_action:
14737  * @self: a #ClutterActor
14738  * @action: a #ClutterAction
14739  *
14740  * Removes @action from the list of actions applied to @self
14741  *
14742  * The reference held by @self on the #ClutterAction will be released
14743  *
14744  * Since: 1.4
14745  */
14746 void
14747 clutter_actor_remove_action (ClutterActor  *self,
14748                              ClutterAction *action)
14749 {
14750   ClutterActorPrivate *priv;
14751
14752   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14753   g_return_if_fail (CLUTTER_IS_ACTION (action));
14754
14755   priv = self->priv;
14756
14757   if (priv->actions == NULL)
14758     return;
14759
14760   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14761
14762   if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
14763     g_clear_object (&priv->actions);
14764
14765   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14766 }
14767
14768 /**
14769  * clutter_actor_remove_action_by_name:
14770  * @self: a #ClutterActor
14771  * @name: the name of the action to remove
14772  *
14773  * Removes the #ClutterAction with the given name from the list
14774  * of actions applied to @self
14775  *
14776  * Since: 1.4
14777  */
14778 void
14779 clutter_actor_remove_action_by_name (ClutterActor *self,
14780                                      const gchar  *name)
14781 {
14782   ClutterActorPrivate *priv;
14783   ClutterActorMeta *meta;
14784
14785   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14786   g_return_if_fail (name != NULL);
14787
14788   priv = self->priv;
14789
14790   if (priv->actions == NULL)
14791     return;
14792
14793   meta = _clutter_meta_group_get_meta (priv->actions, name);
14794   if (meta == NULL)
14795     return;
14796
14797   _clutter_meta_group_remove_meta (priv->actions, meta);
14798
14799   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14800 }
14801
14802 /**
14803  * clutter_actor_get_actions:
14804  * @self: a #ClutterActor
14805  *
14806  * Retrieves the list of actions applied to @self
14807  *
14808  * Return value: (transfer container) (element-type Clutter.Action): a copy
14809  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14810  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14811  *   allocated by the returned #GList
14812  *
14813  * Since: 1.4
14814  */
14815 GList *
14816 clutter_actor_get_actions (ClutterActor *self)
14817 {
14818   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14819
14820   if (self->priv->actions == NULL)
14821     return NULL;
14822
14823   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14824 }
14825
14826 /**
14827  * clutter_actor_get_action:
14828  * @self: a #ClutterActor
14829  * @name: the name of the action to retrieve
14830  *
14831  * Retrieves the #ClutterAction with the given name in the list
14832  * of actions applied to @self
14833  *
14834  * Return value: (transfer none): a #ClutterAction for the given
14835  *   name, or %NULL. The returned #ClutterAction is owned by the
14836  *   actor and it should not be unreferenced directly
14837  *
14838  * Since: 1.4
14839  */
14840 ClutterAction *
14841 clutter_actor_get_action (ClutterActor *self,
14842                           const gchar  *name)
14843 {
14844   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14845   g_return_val_if_fail (name != NULL, NULL);
14846
14847   if (self->priv->actions == NULL)
14848     return NULL;
14849
14850   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14851 }
14852
14853 /**
14854  * clutter_actor_clear_actions:
14855  * @self: a #ClutterActor
14856  *
14857  * Clears the list of actions applied to @self
14858  *
14859  * Since: 1.4
14860  */
14861 void
14862 clutter_actor_clear_actions (ClutterActor *self)
14863 {
14864   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14865
14866   if (self->priv->actions == NULL)
14867     return;
14868
14869   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14870 }
14871
14872 /**
14873  * clutter_actor_add_constraint:
14874  * @self: a #ClutterActor
14875  * @constraint: a #ClutterConstraint
14876  *
14877  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14878  * to @self
14879  *
14880  * The #ClutterActor will hold a reference on the @constraint until
14881  * either clutter_actor_remove_constraint() or
14882  * clutter_actor_clear_constraints() is called.
14883  *
14884  * Since: 1.4
14885  */
14886 void
14887 clutter_actor_add_constraint (ClutterActor      *self,
14888                               ClutterConstraint *constraint)
14889 {
14890   ClutterActorPrivate *priv;
14891
14892   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14893   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14894
14895   priv = self->priv;
14896
14897   if (priv->constraints == NULL)
14898     {
14899       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14900       priv->constraints->actor = self;
14901     }
14902
14903   _clutter_meta_group_add_meta (priv->constraints,
14904                                 CLUTTER_ACTOR_META (constraint));
14905   clutter_actor_queue_relayout (self);
14906
14907   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14908 }
14909
14910 /**
14911  * clutter_actor_add_constraint_with_name:
14912  * @self: a #ClutterActor
14913  * @name: the name to set on the constraint
14914  * @constraint: a #ClutterConstraint
14915  *
14916  * A convenience function for setting the name of a #ClutterConstraint
14917  * while adding it to the list of constraints applied to @self
14918  *
14919  * This function is the logical equivalent of:
14920  *
14921  * |[
14922  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14923  *   clutter_actor_add_constraint (self, constraint);
14924  * ]|
14925  *
14926  * Since: 1.4
14927  */
14928 void
14929 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14930                                         const gchar       *name,
14931                                         ClutterConstraint *constraint)
14932 {
14933   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14934   g_return_if_fail (name != NULL);
14935   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14936
14937   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14938   clutter_actor_add_constraint (self, constraint);
14939 }
14940
14941 /**
14942  * clutter_actor_remove_constraint:
14943  * @self: a #ClutterActor
14944  * @constraint: a #ClutterConstraint
14945  *
14946  * Removes @constraint from the list of constraints applied to @self
14947  *
14948  * The reference held by @self on the #ClutterConstraint will be released
14949  *
14950  * Since: 1.4
14951  */
14952 void
14953 clutter_actor_remove_constraint (ClutterActor      *self,
14954                                  ClutterConstraint *constraint)
14955 {
14956   ClutterActorPrivate *priv;
14957
14958   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14959   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14960
14961   priv = self->priv;
14962
14963   if (priv->constraints == NULL)
14964     return;
14965
14966   _clutter_meta_group_remove_meta (priv->constraints,
14967                                    CLUTTER_ACTOR_META (constraint));
14968
14969   if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
14970     g_clear_object (&priv->constraints);
14971
14972   clutter_actor_queue_relayout (self);
14973
14974   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14975 }
14976
14977 /**
14978  * clutter_actor_remove_constraint_by_name:
14979  * @self: a #ClutterActor
14980  * @name: the name of the constraint to remove
14981  *
14982  * Removes the #ClutterConstraint with the given name from the list
14983  * of constraints applied to @self
14984  *
14985  * Since: 1.4
14986  */
14987 void
14988 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14989                                          const gchar  *name)
14990 {
14991   ClutterActorPrivate *priv;
14992   ClutterActorMeta *meta;
14993
14994   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14995   g_return_if_fail (name != NULL);
14996
14997   priv = self->priv;
14998
14999   if (priv->constraints == NULL)
15000     return;
15001
15002   meta = _clutter_meta_group_get_meta (priv->constraints, name);
15003   if (meta == NULL)
15004     return;
15005
15006   _clutter_meta_group_remove_meta (priv->constraints, meta);
15007   clutter_actor_queue_relayout (self);
15008 }
15009
15010 /**
15011  * clutter_actor_get_constraints:
15012  * @self: a #ClutterActor
15013  *
15014  * Retrieves the list of constraints applied to @self
15015  *
15016  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15017  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15018  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15019  *   allocated by the returned #GList
15020  *
15021  * Since: 1.4
15022  */
15023 GList *
15024 clutter_actor_get_constraints (ClutterActor *self)
15025 {
15026   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15027
15028   if (self->priv->constraints == NULL)
15029     return NULL;
15030
15031   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15032 }
15033
15034 /**
15035  * clutter_actor_get_constraint:
15036  * @self: a #ClutterActor
15037  * @name: the name of the constraint to retrieve
15038  *
15039  * Retrieves the #ClutterConstraint with the given name in the list
15040  * of constraints applied to @self
15041  *
15042  * Return value: (transfer none): a #ClutterConstraint for the given
15043  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15044  *   actor and it should not be unreferenced directly
15045  *
15046  * Since: 1.4
15047  */
15048 ClutterConstraint *
15049 clutter_actor_get_constraint (ClutterActor *self,
15050                               const gchar  *name)
15051 {
15052   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15053   g_return_val_if_fail (name != NULL, NULL);
15054
15055   if (self->priv->constraints == NULL)
15056     return NULL;
15057
15058   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15059 }
15060
15061 /**
15062  * clutter_actor_clear_constraints:
15063  * @self: a #ClutterActor
15064  *
15065  * Clears the list of constraints applied to @self
15066  *
15067  * Since: 1.4
15068  */
15069 void
15070 clutter_actor_clear_constraints (ClutterActor *self)
15071 {
15072   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15073
15074   if (self->priv->constraints == NULL)
15075     return;
15076
15077   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15078
15079   clutter_actor_queue_relayout (self);
15080 }
15081
15082 /**
15083  * clutter_actor_set_clip_to_allocation:
15084  * @self: a #ClutterActor
15085  * @clip_set: %TRUE to apply a clip tracking the allocation
15086  *
15087  * Sets whether @self should be clipped to the same size as its
15088  * allocation
15089  *
15090  * Since: 1.4
15091  */
15092 void
15093 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15094                                       gboolean      clip_set)
15095 {
15096   ClutterActorPrivate *priv;
15097
15098   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15099
15100   clip_set = !!clip_set;
15101
15102   priv = self->priv;
15103
15104   if (priv->clip_to_allocation != clip_set)
15105     {
15106       priv->clip_to_allocation = clip_set;
15107
15108       clutter_actor_queue_redraw (self);
15109
15110       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15111     }
15112 }
15113
15114 /**
15115  * clutter_actor_get_clip_to_allocation:
15116  * @self: a #ClutterActor
15117  *
15118  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15119  *
15120  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15121  *
15122  * Since: 1.4
15123  */
15124 gboolean
15125 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15126 {
15127   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15128
15129   return self->priv->clip_to_allocation;
15130 }
15131
15132 /**
15133  * clutter_actor_add_effect:
15134  * @self: a #ClutterActor
15135  * @effect: a #ClutterEffect
15136  *
15137  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15138  *
15139  * The #ClutterActor will hold a reference on the @effect until either
15140  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15141  * called.
15142  *
15143  * Since: 1.4
15144  */
15145 void
15146 clutter_actor_add_effect (ClutterActor  *self,
15147                           ClutterEffect *effect)
15148 {
15149   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15150   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15151
15152   _clutter_actor_add_effect_internal (self, effect);
15153
15154   clutter_actor_queue_redraw (self);
15155
15156   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15157 }
15158
15159 /**
15160  * clutter_actor_add_effect_with_name:
15161  * @self: a #ClutterActor
15162  * @name: the name to set on the effect
15163  * @effect: a #ClutterEffect
15164  *
15165  * A convenience function for setting the name of a #ClutterEffect
15166  * while adding it to the list of effectss applied to @self
15167  *
15168  * This function is the logical equivalent of:
15169  *
15170  * |[
15171  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15172  *   clutter_actor_add_effect (self, effect);
15173  * ]|
15174  *
15175  * Since: 1.4
15176  */
15177 void
15178 clutter_actor_add_effect_with_name (ClutterActor  *self,
15179                                     const gchar   *name,
15180                                     ClutterEffect *effect)
15181 {
15182   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15183   g_return_if_fail (name != NULL);
15184   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15185
15186   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15187   clutter_actor_add_effect (self, effect);
15188 }
15189
15190 /**
15191  * clutter_actor_remove_effect:
15192  * @self: a #ClutterActor
15193  * @effect: a #ClutterEffect
15194  *
15195  * Removes @effect from the list of effects applied to @self
15196  *
15197  * The reference held by @self on the #ClutterEffect will be released
15198  *
15199  * Since: 1.4
15200  */
15201 void
15202 clutter_actor_remove_effect (ClutterActor  *self,
15203                              ClutterEffect *effect)
15204 {
15205   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15206   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15207
15208   _clutter_actor_remove_effect_internal (self, effect);
15209
15210   clutter_actor_queue_redraw (self);
15211
15212   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15213 }
15214
15215 /**
15216  * clutter_actor_remove_effect_by_name:
15217  * @self: a #ClutterActor
15218  * @name: the name of the effect to remove
15219  *
15220  * Removes the #ClutterEffect with the given name from the list
15221  * of effects applied to @self
15222  *
15223  * Since: 1.4
15224  */
15225 void
15226 clutter_actor_remove_effect_by_name (ClutterActor *self,
15227                                      const gchar  *name)
15228 {
15229   ClutterActorPrivate *priv;
15230   ClutterActorMeta *meta;
15231
15232   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15233   g_return_if_fail (name != NULL);
15234
15235   priv = self->priv;
15236
15237   if (priv->effects == NULL)
15238     return;
15239
15240   meta = _clutter_meta_group_get_meta (priv->effects, name);
15241   if (meta == NULL)
15242     return;
15243
15244   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15245 }
15246
15247 /**
15248  * clutter_actor_get_effects:
15249  * @self: a #ClutterActor
15250  *
15251  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15252  *
15253  * Return value: (transfer container) (element-type Clutter.Effect): a list
15254  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15255  *   list are owned by Clutter and they should not be freed. You should
15256  *   free the returned list using g_list_free() when done
15257  *
15258  * Since: 1.4
15259  */
15260 GList *
15261 clutter_actor_get_effects (ClutterActor *self)
15262 {
15263   ClutterActorPrivate *priv;
15264
15265   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15266
15267   priv = self->priv;
15268
15269   if (priv->effects == NULL)
15270     return NULL;
15271
15272   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15273 }
15274
15275 /**
15276  * clutter_actor_get_effect:
15277  * @self: a #ClutterActor
15278  * @name: the name of the effect to retrieve
15279  *
15280  * Retrieves the #ClutterEffect with the given name in the list
15281  * of effects applied to @self
15282  *
15283  * Return value: (transfer none): a #ClutterEffect for the given
15284  *   name, or %NULL. The returned #ClutterEffect is owned by the
15285  *   actor and it should not be unreferenced directly
15286  *
15287  * Since: 1.4
15288  */
15289 ClutterEffect *
15290 clutter_actor_get_effect (ClutterActor *self,
15291                           const gchar  *name)
15292 {
15293   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15294   g_return_val_if_fail (name != NULL, NULL);
15295
15296   if (self->priv->effects == NULL)
15297     return NULL;
15298
15299   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15300 }
15301
15302 /**
15303  * clutter_actor_clear_effects:
15304  * @self: a #ClutterActor
15305  *
15306  * Clears the list of effects applied to @self
15307  *
15308  * Since: 1.4
15309  */
15310 void
15311 clutter_actor_clear_effects (ClutterActor *self)
15312 {
15313   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15314
15315   if (self->priv->effects == NULL)
15316     return;
15317
15318   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15319
15320   clutter_actor_queue_redraw (self);
15321 }
15322
15323 /**
15324  * clutter_actor_has_key_focus:
15325  * @self: a #ClutterActor
15326  *
15327  * Checks whether @self is the #ClutterActor that has key focus
15328  *
15329  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15330  *
15331  * Since: 1.4
15332  */
15333 gboolean
15334 clutter_actor_has_key_focus (ClutterActor *self)
15335 {
15336   ClutterActor *stage;
15337
15338   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15339
15340   stage = _clutter_actor_get_stage_internal (self);
15341   if (stage == NULL)
15342     return FALSE;
15343
15344   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15345 }
15346
15347 static gboolean
15348 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15349                                       ClutterPaintVolume *pv)
15350 {
15351   ClutterActorPrivate *priv = self->priv;
15352
15353   /* Actors are only expected to report a valid paint volume
15354    * while they have a valid allocation. */
15355   if (G_UNLIKELY (priv->needs_allocation))
15356     {
15357       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15358                     "Actor needs allocation",
15359                     _clutter_actor_get_debug_name (self));
15360       return FALSE;
15361     }
15362
15363   /* Check if there are any handlers connected to the paint
15364    * signal. If there are then all bets are off for what the paint
15365    * volume for this actor might possibly be!
15366    *
15367    * XXX: It's expected that this is going to end up being quite a
15368    * costly check to have to do here, but we haven't come up with
15369    * another solution that can reliably catch paint signal handlers at
15370    * the right time to either avoid artefacts due to invalid stage
15371    * clipping or due to incorrect culling.
15372    *
15373    * Previously we checked in clutter_actor_paint(), but at that time
15374    * we may already be using a stage clip that could be derived from
15375    * an invalid paint-volume. We used to try and handle that by
15376    * queuing a follow up, unclipped, redraw but still the previous
15377    * checking wasn't enough to catch invalid volumes involved in
15378    * culling (considering that containers may derive their volume from
15379    * children that haven't yet been painted)
15380    *
15381    * Longer term, improved solutions could be:
15382    * - Disallow painting in the paint signal, only allow using it
15383    *   for tracking when paints happen. We can add another API that
15384    *   allows monkey patching the paint of arbitrary actors but in a
15385    *   more controlled way and that also supports modifying the
15386    *   paint-volume.
15387    * - If we could be notified somehow when signal handlers are
15388    *   connected we wouldn't have to poll for handlers like this.
15389    */
15390   if (g_signal_has_handler_pending (self,
15391                                     actor_signals[PAINT],
15392                                     0,
15393                                     TRUE))
15394     {
15395       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15396                     "Actor has \"paint\" signal handlers",
15397                     _clutter_actor_get_debug_name (self));
15398       return FALSE;
15399     }
15400
15401   _clutter_paint_volume_init_static (pv, self);
15402
15403   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15404     {
15405       clutter_paint_volume_free (pv);
15406       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15407                     "Actor failed to report a volume",
15408                     _clutter_actor_get_debug_name (self));
15409       return FALSE;
15410     }
15411
15412   /* since effects can modify the paint volume, we allow them to actually
15413    * do this by making get_paint_volume() "context sensitive"
15414    */
15415   if (priv->effects != NULL)
15416     {
15417       if (priv->current_effect != NULL)
15418         {
15419           const GList *effects, *l;
15420
15421           /* if we are being called from within the paint sequence of
15422            * an actor, get the paint volume up to the current effect
15423            */
15424           effects = _clutter_meta_group_peek_metas (priv->effects);
15425           for (l = effects;
15426                l != NULL || (l != NULL && l->data != priv->current_effect);
15427                l = l->next)
15428             {
15429               if (!_clutter_effect_get_paint_volume (l->data, pv))
15430                 {
15431                   clutter_paint_volume_free (pv);
15432                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15433                                 "Effect (%s) failed to report a volume",
15434                                 _clutter_actor_get_debug_name (self),
15435                                 _clutter_actor_meta_get_debug_name (l->data));
15436                   return FALSE;
15437                 }
15438             }
15439         }
15440       else
15441         {
15442           const GList *effects, *l;
15443
15444           /* otherwise, get the cumulative volume */
15445           effects = _clutter_meta_group_peek_metas (priv->effects);
15446           for (l = effects; l != NULL; l = l->next)
15447             if (!_clutter_effect_get_paint_volume (l->data, pv))
15448               {
15449                 clutter_paint_volume_free (pv);
15450                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15451                               "Effect (%s) failed to report a volume",
15452                               _clutter_actor_get_debug_name (self),
15453                               _clutter_actor_meta_get_debug_name (l->data));
15454                 return FALSE;
15455               }
15456         }
15457     }
15458
15459   return TRUE;
15460 }
15461
15462 /* The public clutter_actor_get_paint_volume API returns a const
15463  * pointer since we return a pointer directly to the cached
15464  * PaintVolume associated with the actor and don't want the user to
15465  * inadvertently modify it, but for internal uses we sometimes need
15466  * access to the same PaintVolume but need to apply some book-keeping
15467  * modifications to it so we don't want a const pointer.
15468  */
15469 static ClutterPaintVolume *
15470 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15471 {
15472   ClutterActorPrivate *priv;
15473
15474   priv = self->priv;
15475
15476   if (priv->paint_volume_valid)
15477     clutter_paint_volume_free (&priv->paint_volume);
15478
15479   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15480     {
15481       priv->paint_volume_valid = TRUE;
15482       return &priv->paint_volume;
15483     }
15484   else
15485     {
15486       priv->paint_volume_valid = FALSE;
15487       return NULL;
15488     }
15489 }
15490
15491 /**
15492  * clutter_actor_get_paint_volume:
15493  * @self: a #ClutterActor
15494  *
15495  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15496  * when a paint volume can't be determined.
15497  *
15498  * The paint volume is defined as the 3D space occupied by an actor
15499  * when being painted.
15500  *
15501  * This function will call the <function>get_paint_volume()</function>
15502  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15503  * should not usually care about overriding the default implementation,
15504  * unless they are, for instance: painting outside their allocation, or
15505  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15506  * 3D depth).
15507  *
15508  * <note>2D actors overriding <function>get_paint_volume()</function>
15509  * ensure their volume has a depth of 0. (This will be true so long as
15510  * you don't call clutter_paint_volume_set_depth().)</note>
15511  *
15512  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15513  *   or %NULL if no volume could be determined. The returned pointer
15514  *   is not guaranteed to be valid across multiple frames; if you want
15515  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15516  *
15517  * Since: 1.6
15518  */
15519 const ClutterPaintVolume *
15520 clutter_actor_get_paint_volume (ClutterActor *self)
15521 {
15522   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15523
15524   return _clutter_actor_get_paint_volume_mutable (self);
15525 }
15526
15527 /**
15528  * clutter_actor_get_transformed_paint_volume:
15529  * @self: a #ClutterActor
15530  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15531  *    (or %NULL for the stage)
15532  *
15533  * Retrieves the 3D paint volume of an actor like
15534  * clutter_actor_get_paint_volume() does (Please refer to the
15535  * documentation of clutter_actor_get_paint_volume() for more
15536  * details.) and it additionally transforms the paint volume into the
15537  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15538  * is passed for @relative_to_ancestor)
15539  *
15540  * This can be used by containers that base their paint volume on
15541  * the volume of their children. Such containers can query the
15542  * transformed paint volume of all of its children and union them
15543  * together using clutter_paint_volume_union().
15544  *
15545  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15546  *   or %NULL if no volume could be determined. The returned pointer is
15547  *   not guaranteed to be valid across multiple frames; if you wish to
15548  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15549  *
15550  * Since: 1.6
15551  */
15552 const ClutterPaintVolume *
15553 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15554                                             ClutterActor *relative_to_ancestor)
15555 {
15556   const ClutterPaintVolume *volume;
15557   ClutterActor *stage;
15558   ClutterPaintVolume *transformed_volume;
15559
15560   stage = _clutter_actor_get_stage_internal (self);
15561   if (G_UNLIKELY (stage == NULL))
15562     return NULL;
15563
15564   if (relative_to_ancestor == NULL)
15565     relative_to_ancestor = stage;
15566
15567   volume = clutter_actor_get_paint_volume (self);
15568   if (volume == NULL)
15569     return NULL;
15570
15571   transformed_volume =
15572     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15573
15574   _clutter_paint_volume_copy_static (volume, transformed_volume);
15575
15576   _clutter_paint_volume_transform_relative (transformed_volume,
15577                                             relative_to_ancestor);
15578
15579   return transformed_volume;
15580 }
15581
15582 /**
15583  * clutter_actor_get_paint_box:
15584  * @self: a #ClutterActor
15585  * @box: (out): return location for a #ClutterActorBox
15586  *
15587  * Retrieves the paint volume of the passed #ClutterActor, and
15588  * transforms it into a 2D bounding box in stage coordinates.
15589  *
15590  * This function is useful to determine the on screen area occupied by
15591  * the actor. The box is only an approximation and may often be
15592  * considerably larger due to the optimizations used to calculate the
15593  * box. The box is never smaller though, so it can reliably be used
15594  * for culling.
15595  *
15596  * There are times when a 2D paint box can't be determined, e.g.
15597  * because the actor isn't yet parented under a stage or because
15598  * the actor is unable to determine a paint volume.
15599  *
15600  * Return value: %TRUE if a 2D paint box could be determined, else
15601  * %FALSE.
15602  *
15603  * Since: 1.6
15604  */
15605 gboolean
15606 clutter_actor_get_paint_box (ClutterActor    *self,
15607                              ClutterActorBox *box)
15608 {
15609   ClutterActor *stage;
15610   ClutterPaintVolume *pv;
15611
15612   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15613   g_return_val_if_fail (box != NULL, FALSE);
15614
15615   stage = _clutter_actor_get_stage_internal (self);
15616   if (G_UNLIKELY (!stage))
15617     return FALSE;
15618
15619   pv = _clutter_actor_get_paint_volume_mutable (self);
15620   if (G_UNLIKELY (!pv))
15621     return FALSE;
15622
15623   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15624
15625   return TRUE;
15626 }
15627
15628 /**
15629  * clutter_actor_has_overlaps:
15630  * @self: A #ClutterActor
15631  *
15632  * Asks the actor's implementation whether it may contain overlapping
15633  * primitives.
15634  *
15635  * For example; Clutter may use this to determine whether the painting
15636  * should be redirected to an offscreen buffer to correctly implement
15637  * the opacity property.
15638  *
15639  * Custom actors can override the default response by implementing the
15640  * #ClutterActor <function>has_overlaps</function> virtual function. See
15641  * clutter_actor_set_offscreen_redirect() for more information.
15642  *
15643  * Return value: %TRUE if the actor may have overlapping primitives, and
15644  *   %FALSE otherwise
15645  *
15646  * Since: 1.8
15647  */
15648 gboolean
15649 clutter_actor_has_overlaps (ClutterActor *self)
15650 {
15651   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15652
15653   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15654 }
15655
15656 /**
15657  * clutter_actor_has_effects:
15658  * @self: A #ClutterActor
15659  *
15660  * Returns whether the actor has any effects applied.
15661  *
15662  * Return value: %TRUE if the actor has any effects,
15663  *   %FALSE otherwise
15664  *
15665  * Since: 1.10
15666  */
15667 gboolean
15668 clutter_actor_has_effects (ClutterActor *self)
15669 {
15670   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15671
15672   if (self->priv->effects == NULL)
15673     return FALSE;
15674
15675   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15676 }
15677
15678 /**
15679  * clutter_actor_has_constraints:
15680  * @self: A #ClutterActor
15681  *
15682  * Returns whether the actor has any constraints applied.
15683  *
15684  * Return value: %TRUE if the actor has any constraints,
15685  *   %FALSE otherwise
15686  *
15687  * Since: 1.10
15688  */
15689 gboolean
15690 clutter_actor_has_constraints (ClutterActor *self)
15691 {
15692   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15693
15694   return self->priv->constraints != NULL;
15695 }
15696
15697 /**
15698  * clutter_actor_has_actions:
15699  * @self: A #ClutterActor
15700  *
15701  * Returns whether the actor has any actions applied.
15702  *
15703  * Return value: %TRUE if the actor has any actions,
15704  *   %FALSE otherwise
15705  *
15706  * Since: 1.10
15707  */
15708 gboolean
15709 clutter_actor_has_actions (ClutterActor *self)
15710 {
15711   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15712
15713   return self->priv->actions != NULL;
15714 }
15715
15716 /**
15717  * clutter_actor_get_n_children:
15718  * @self: a #ClutterActor
15719  *
15720  * Retrieves the number of children of @self.
15721  *
15722  * Return value: the number of children of an actor
15723  *
15724  * Since: 1.10
15725  */
15726 gint
15727 clutter_actor_get_n_children (ClutterActor *self)
15728 {
15729   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15730
15731   return self->priv->n_children;
15732 }
15733
15734 /**
15735  * clutter_actor_get_child_at_index:
15736  * @self: a #ClutterActor
15737  * @index_: the position in the list of children
15738  *
15739  * Retrieves the actor at the given @index_ inside the list of
15740  * children of @self.
15741  *
15742  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15743  *
15744  * Since: 1.10
15745  */
15746 ClutterActor *
15747 clutter_actor_get_child_at_index (ClutterActor *self,
15748                                   gint          index_)
15749 {
15750   ClutterActor *iter;
15751   int i;
15752
15753   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15754   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15755
15756   for (iter = self->priv->first_child, i = 0;
15757        iter != NULL && i < index_;
15758        iter = iter->priv->next_sibling, i += 1)
15759     ;
15760
15761   return iter;
15762 }
15763
15764 /*< private >
15765  * _clutter_actor_foreach_child:
15766  * @actor: The actor whos children you want to iterate
15767  * @callback: The function to call for each child
15768  * @user_data: Private data to pass to @callback
15769  *
15770  * Calls a given @callback once for each child of the specified @actor and
15771  * passing the @user_data pointer each time.
15772  *
15773  * Return value: returns %TRUE if all children were iterated, else
15774  *    %FALSE if a callback broke out of iteration early.
15775  */
15776 gboolean
15777 _clutter_actor_foreach_child (ClutterActor           *self,
15778                               ClutterForeachCallback  callback,
15779                               gpointer                user_data)
15780 {
15781   ClutterActor *iter;
15782   gboolean cont;
15783
15784   if (self->priv->first_child == NULL)
15785     return TRUE;
15786
15787   cont = TRUE;
15788   iter = self->priv->first_child;
15789
15790   /* we use this form so that it's safe to change the children
15791    * list while iterating it
15792    */
15793   while (cont && iter != NULL)
15794     {
15795       ClutterActor *next = iter->priv->next_sibling;
15796
15797       cont = callback (iter, user_data);
15798
15799       iter = next;
15800     }
15801
15802   return cont;
15803 }
15804
15805 #if 0
15806 /* For debugging purposes this gives us a simple way to print out
15807  * the scenegraph e.g in gdb using:
15808  * [|
15809  *   _clutter_actor_traverse (stage,
15810  *                            0,
15811  *                            clutter_debug_print_actor_cb,
15812  *                            NULL,
15813  *                            NULL);
15814  * |]
15815  */
15816 static ClutterActorTraverseVisitFlags
15817 clutter_debug_print_actor_cb (ClutterActor *actor,
15818                               int depth,
15819                               void *user_data)
15820 {
15821   g_print ("%*s%s:%p\n",
15822            depth * 2, "",
15823            _clutter_actor_get_debug_name (actor),
15824            actor);
15825
15826   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15827 }
15828 #endif
15829
15830 static void
15831 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15832                                  ClutterTraverseCallback callback,
15833                                  gpointer                user_data)
15834 {
15835   GQueue *queue = g_queue_new ();
15836   ClutterActor dummy;
15837   int current_depth = 0;
15838
15839   g_queue_push_tail (queue, actor);
15840   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15841
15842   while ((actor = g_queue_pop_head (queue)))
15843     {
15844       ClutterActorTraverseVisitFlags flags;
15845
15846       if (actor == &dummy)
15847         {
15848           current_depth++;
15849           g_queue_push_tail (queue, &dummy);
15850           continue;
15851         }
15852
15853       flags = callback (actor, current_depth, user_data);
15854       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15855         break;
15856       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15857         {
15858           ClutterActor *iter;
15859
15860           for (iter = actor->priv->first_child;
15861                iter != NULL;
15862                iter = iter->priv->next_sibling)
15863             {
15864               g_queue_push_tail (queue, iter);
15865             }
15866         }
15867     }
15868
15869   g_queue_free (queue);
15870 }
15871
15872 static ClutterActorTraverseVisitFlags
15873 _clutter_actor_traverse_depth (ClutterActor           *actor,
15874                                ClutterTraverseCallback before_children_callback,
15875                                ClutterTraverseCallback after_children_callback,
15876                                int                     current_depth,
15877                                gpointer                user_data)
15878 {
15879   ClutterActorTraverseVisitFlags flags;
15880
15881   flags = before_children_callback (actor, current_depth, user_data);
15882   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15883     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15884
15885   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15886     {
15887       ClutterActor *iter;
15888
15889       for (iter = actor->priv->first_child;
15890            iter != NULL;
15891            iter = iter->priv->next_sibling)
15892         {
15893           flags = _clutter_actor_traverse_depth (iter,
15894                                                  before_children_callback,
15895                                                  after_children_callback,
15896                                                  current_depth + 1,
15897                                                  user_data);
15898
15899           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15900             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15901         }
15902     }
15903
15904   if (after_children_callback)
15905     return after_children_callback (actor, current_depth, user_data);
15906   else
15907     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15908 }
15909
15910 /* _clutter_actor_traverse:
15911  * @actor: The actor to start traversing the graph from
15912  * @flags: These flags may affect how the traversal is done
15913  * @before_children_callback: A function to call before visiting the
15914  *   children of the current actor.
15915  * @after_children_callback: A function to call after visiting the
15916  *   children of the current actor. (Ignored if
15917  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15918  * @user_data: The private data to pass to the callbacks
15919  *
15920  * Traverses the scenegraph starting at the specified @actor and
15921  * descending through all its children and its children's children.
15922  * For each actor traversed @before_children_callback and
15923  * @after_children_callback are called with the specified
15924  * @user_data, before and after visiting that actor's children.
15925  *
15926  * The callbacks can return flags that affect the ongoing traversal
15927  * such as by skipping over an actors children or bailing out of
15928  * any further traversing.
15929  */
15930 void
15931 _clutter_actor_traverse (ClutterActor              *actor,
15932                          ClutterActorTraverseFlags  flags,
15933                          ClutterTraverseCallback    before_children_callback,
15934                          ClutterTraverseCallback    after_children_callback,
15935                          gpointer                   user_data)
15936 {
15937   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15938     _clutter_actor_traverse_breadth (actor,
15939                                      before_children_callback,
15940                                      user_data);
15941   else /* DEPTH_FIRST */
15942     _clutter_actor_traverse_depth (actor,
15943                                    before_children_callback,
15944                                    after_children_callback,
15945                                    0, /* start depth */
15946                                    user_data);
15947 }
15948
15949 static void
15950 on_layout_manager_changed (ClutterLayoutManager *manager,
15951                            ClutterActor         *self)
15952 {
15953   clutter_actor_queue_relayout (self);
15954 }
15955
15956 /**
15957  * clutter_actor_set_layout_manager:
15958  * @self: a #ClutterActor
15959  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15960  *
15961  * Sets the #ClutterLayoutManager delegate object that will be used to
15962  * lay out the children of @self.
15963  *
15964  * The #ClutterActor will take a reference on the passed @manager which
15965  * will be released either when the layout manager is removed, or when
15966  * the actor is destroyed.
15967  *
15968  * Since: 1.10
15969  */
15970 void
15971 clutter_actor_set_layout_manager (ClutterActor         *self,
15972                                   ClutterLayoutManager *manager)
15973 {
15974   ClutterActorPrivate *priv;
15975
15976   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15977   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15978
15979   priv = self->priv;
15980
15981   if (priv->layout_manager != NULL)
15982     {
15983       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15984                                             G_CALLBACK (on_layout_manager_changed),
15985                                             self);
15986       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15987       g_clear_object (&priv->layout_manager);
15988     }
15989
15990   priv->layout_manager = manager;
15991
15992   if (priv->layout_manager != NULL)
15993     {
15994       g_object_ref_sink (priv->layout_manager);
15995       clutter_layout_manager_set_container (priv->layout_manager,
15996                                             CLUTTER_CONTAINER (self));
15997       g_signal_connect (priv->layout_manager, "layout-changed",
15998                         G_CALLBACK (on_layout_manager_changed),
15999                         self);
16000     }
16001
16002   clutter_actor_queue_relayout (self);
16003
16004   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16005 }
16006
16007 /**
16008  * clutter_actor_get_layout_manager:
16009  * @self: a #ClutterActor
16010  *
16011  * Retrieves the #ClutterLayoutManager used by @self.
16012  *
16013  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16014  *   or %NULL
16015  *
16016  * Since: 1.10
16017  */
16018 ClutterLayoutManager *
16019 clutter_actor_get_layout_manager (ClutterActor *self)
16020 {
16021   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16022
16023   return self->priv->layout_manager;
16024 }
16025
16026 static const ClutterLayoutInfo default_layout_info = {
16027   CLUTTER_POINT_INIT_ZERO,      /* fixed-pos */
16028   { 0, 0, 0, 0 },               /* margin */
16029   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
16030   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
16031   CLUTTER_SIZE_INIT_ZERO,       /* minimum */
16032   CLUTTER_SIZE_INIT_ZERO,       /* natural */
16033 };
16034
16035 static void
16036 layout_info_free (gpointer data)
16037 {
16038   if (G_LIKELY (data != NULL))
16039     g_slice_free (ClutterLayoutInfo, data);
16040 }
16041
16042 /*< private >
16043  * _clutter_actor_get_layout_info:
16044  * @self: a #ClutterActor
16045  *
16046  * Retrieves a pointer to the ClutterLayoutInfo structure.
16047  *
16048  * If the actor does not have a ClutterLayoutInfo associated to it, one
16049  * will be created and initialized to the default values.
16050  *
16051  * This function should be used for setters.
16052  *
16053  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16054  * instead.
16055  *
16056  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16057  */
16058 ClutterLayoutInfo *
16059 _clutter_actor_get_layout_info (ClutterActor *self)
16060 {
16061   ClutterLayoutInfo *retval;
16062
16063   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16064   if (retval == NULL)
16065     {
16066       retval = g_slice_new (ClutterLayoutInfo);
16067
16068       *retval = default_layout_info;
16069
16070       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16071                                retval,
16072                                layout_info_free);
16073     }
16074
16075   return retval;
16076 }
16077
16078 /*< private >
16079  * _clutter_actor_get_layout_info_or_defaults:
16080  * @self: a #ClutterActor
16081  *
16082  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16083  *
16084  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16085  * then the default structure will be returned.
16086  *
16087  * This function should only be used for getters.
16088  *
16089  * Return value: a const pointer to the ClutterLayoutInfo structure
16090  */
16091 const ClutterLayoutInfo *
16092 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16093 {
16094   const ClutterLayoutInfo *info;
16095
16096   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16097   if (info == NULL)
16098     return &default_layout_info;
16099
16100   return info;
16101 }
16102
16103 /**
16104  * clutter_actor_set_x_align:
16105  * @self: a #ClutterActor
16106  * @x_align: the horizontal alignment policy
16107  *
16108  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16109  * actor received extra horizontal space.
16110  *
16111  * See also the #ClutterActor:x-align property.
16112  *
16113  * Since: 1.10
16114  */
16115 void
16116 clutter_actor_set_x_align (ClutterActor      *self,
16117                            ClutterActorAlign  x_align)
16118 {
16119   ClutterLayoutInfo *info;
16120
16121   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16122
16123   info = _clutter_actor_get_layout_info (self);
16124
16125   if (info->x_align != x_align)
16126     {
16127       info->x_align = x_align;
16128
16129       clutter_actor_queue_relayout (self);
16130
16131       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16132     }
16133 }
16134
16135 /**
16136  * clutter_actor_get_x_align:
16137  * @self: a #ClutterActor
16138  *
16139  * Retrieves the horizontal alignment policy set using
16140  * clutter_actor_set_x_align().
16141  *
16142  * Return value: the horizontal alignment policy.
16143  *
16144  * Since: 1.10
16145  */
16146 ClutterActorAlign
16147 clutter_actor_get_x_align (ClutterActor *self)
16148 {
16149   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16150
16151   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16152 }
16153
16154 /**
16155  * clutter_actor_set_y_align:
16156  * @self: a #ClutterActor
16157  * @y_align: the vertical alignment policy
16158  *
16159  * Sets the vertical alignment policy of a #ClutterActor, in case the
16160  * actor received extra vertical space.
16161  *
16162  * See also the #ClutterActor:y-align property.
16163  *
16164  * Since: 1.10
16165  */
16166 void
16167 clutter_actor_set_y_align (ClutterActor      *self,
16168                            ClutterActorAlign  y_align)
16169 {
16170   ClutterLayoutInfo *info;
16171
16172   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16173
16174   info = _clutter_actor_get_layout_info (self);
16175
16176   if (info->y_align != y_align)
16177     {
16178       info->y_align = y_align;
16179
16180       clutter_actor_queue_relayout (self);
16181
16182       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16183     }
16184 }
16185
16186 /**
16187  * clutter_actor_get_y_align:
16188  * @self: a #ClutterActor
16189  *
16190  * Retrieves the vertical alignment policy set using
16191  * clutter_actor_set_y_align().
16192  *
16193  * Return value: the vertical alignment policy.
16194  *
16195  * Since: 1.10
16196  */
16197 ClutterActorAlign
16198 clutter_actor_get_y_align (ClutterActor *self)
16199 {
16200   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16201
16202   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16203 }
16204
16205 /**
16206  * clutter_actor_set_margin:
16207  * @self: a #ClutterActor
16208  * @margin: a #ClutterMargin
16209  *
16210  * Sets all the components of the margin of a #ClutterActor.
16211  *
16212  * Since: 1.10
16213  */
16214 void
16215 clutter_actor_set_margin (ClutterActor        *self,
16216                           const ClutterMargin *margin)
16217 {
16218   ClutterLayoutInfo *info;
16219   gboolean changed;
16220   GObject *obj;
16221
16222   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16223   g_return_if_fail (margin != NULL);
16224
16225   obj = G_OBJECT (self);
16226   changed = FALSE;
16227
16228   g_object_freeze_notify (obj);
16229
16230   info = _clutter_actor_get_layout_info (self);
16231
16232   if (info->margin.top != margin->top)
16233     {
16234       info->margin.top = margin->top;
16235       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16236       changed = TRUE;
16237     }
16238
16239   if (info->margin.right != margin->right)
16240     {
16241       info->margin.right = margin->right;
16242       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16243       changed = TRUE;
16244     }
16245
16246   if (info->margin.bottom != margin->bottom)
16247     {
16248       info->margin.bottom = margin->bottom;
16249       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16250       changed = TRUE;
16251     }
16252
16253   if (info->margin.left != margin->left)
16254     {
16255       info->margin.left = margin->left;
16256       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16257       changed = TRUE;
16258     }
16259
16260   if (changed)
16261     clutter_actor_queue_relayout (self);
16262
16263   g_object_thaw_notify (obj);
16264 }
16265
16266 /**
16267  * clutter_actor_get_margin:
16268  * @self: a #ClutterActor
16269  * @margin: (out caller-allocates): return location for a #ClutterMargin
16270  *
16271  * Retrieves all the components of the margin of a #ClutterActor.
16272  *
16273  * Since: 1.10
16274  */
16275 void
16276 clutter_actor_get_margin (ClutterActor  *self,
16277                           ClutterMargin *margin)
16278 {
16279   const ClutterLayoutInfo *info;
16280
16281   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16282   g_return_if_fail (margin != NULL);
16283
16284   info = _clutter_actor_get_layout_info_or_defaults (self);
16285
16286   *margin = info->margin;
16287 }
16288
16289 /**
16290  * clutter_actor_set_margin_top:
16291  * @self: a #ClutterActor
16292  * @margin: the top margin
16293  *
16294  * Sets the margin from the top of a #ClutterActor.
16295  *
16296  * Since: 1.10
16297  */
16298 void
16299 clutter_actor_set_margin_top (ClutterActor *self,
16300                               gfloat        margin)
16301 {
16302   ClutterLayoutInfo *info;
16303
16304   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16305   g_return_if_fail (margin >= 0.f);
16306
16307   info = _clutter_actor_get_layout_info (self);
16308
16309   if (info->margin.top == margin)
16310     return;
16311
16312   info->margin.top = margin;
16313
16314   clutter_actor_queue_relayout (self);
16315
16316   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16317 }
16318
16319 /**
16320  * clutter_actor_get_margin_top:
16321  * @self: a #ClutterActor
16322  *
16323  * Retrieves the top margin of a #ClutterActor.
16324  *
16325  * Return value: the top margin
16326  *
16327  * Since: 1.10
16328  */
16329 gfloat
16330 clutter_actor_get_margin_top (ClutterActor *self)
16331 {
16332   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16333
16334   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16335 }
16336
16337 /**
16338  * clutter_actor_set_margin_bottom:
16339  * @self: a #ClutterActor
16340  * @margin: the bottom margin
16341  *
16342  * Sets the margin from the bottom of a #ClutterActor.
16343  *
16344  * Since: 1.10
16345  */
16346 void
16347 clutter_actor_set_margin_bottom (ClutterActor *self,
16348                                  gfloat        margin)
16349 {
16350   ClutterLayoutInfo *info;
16351
16352   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16353   g_return_if_fail (margin >= 0.f);
16354
16355   info = _clutter_actor_get_layout_info (self);
16356
16357   if (info->margin.bottom == margin)
16358     return;
16359
16360   info->margin.bottom = margin;
16361
16362   clutter_actor_queue_relayout (self);
16363
16364   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16365 }
16366
16367 /**
16368  * clutter_actor_get_margin_bottom:
16369  * @self: a #ClutterActor
16370  *
16371  * Retrieves the bottom margin of a #ClutterActor.
16372  *
16373  * Return value: the bottom margin
16374  *
16375  * Since: 1.10
16376  */
16377 gfloat
16378 clutter_actor_get_margin_bottom (ClutterActor *self)
16379 {
16380   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16381
16382   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16383 }
16384
16385 /**
16386  * clutter_actor_set_margin_left:
16387  * @self: a #ClutterActor
16388  * @margin: the left margin
16389  *
16390  * Sets the margin from the left of a #ClutterActor.
16391  *
16392  * Since: 1.10
16393  */
16394 void
16395 clutter_actor_set_margin_left (ClutterActor *self,
16396                                gfloat        margin)
16397 {
16398   ClutterLayoutInfo *info;
16399
16400   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16401   g_return_if_fail (margin >= 0.f);
16402
16403   info = _clutter_actor_get_layout_info (self);
16404
16405   if (info->margin.left == margin)
16406     return;
16407
16408   info->margin.left = margin;
16409
16410   clutter_actor_queue_relayout (self);
16411
16412   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16413 }
16414
16415 /**
16416  * clutter_actor_get_margin_left:
16417  * @self: a #ClutterActor
16418  *
16419  * Retrieves the left margin of a #ClutterActor.
16420  *
16421  * Return value: the left margin
16422  *
16423  * Since: 1.10
16424  */
16425 gfloat
16426 clutter_actor_get_margin_left (ClutterActor *self)
16427 {
16428   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16429
16430   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16431 }
16432
16433 /**
16434  * clutter_actor_set_margin_right:
16435  * @self: a #ClutterActor
16436  * @margin: the right margin
16437  *
16438  * Sets the margin from the right of a #ClutterActor.
16439  *
16440  * Since: 1.10
16441  */
16442 void
16443 clutter_actor_set_margin_right (ClutterActor *self,
16444                                 gfloat        margin)
16445 {
16446   ClutterLayoutInfo *info;
16447
16448   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16449   g_return_if_fail (margin >= 0.f);
16450
16451   info = _clutter_actor_get_layout_info (self);
16452
16453   if (info->margin.right == margin)
16454     return;
16455
16456   info->margin.right = margin;
16457
16458   clutter_actor_queue_relayout (self);
16459
16460   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16461 }
16462
16463 /**
16464  * clutter_actor_get_margin_right:
16465  * @self: a #ClutterActor
16466  *
16467  * Retrieves the right margin of a #ClutterActor.
16468  *
16469  * Return value: the right margin
16470  *
16471  * Since: 1.10
16472  */
16473 gfloat
16474 clutter_actor_get_margin_right (ClutterActor *self)
16475 {
16476   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16477
16478   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16479 }
16480
16481 static inline void
16482 clutter_actor_set_background_color_internal (ClutterActor *self,
16483                                              const ClutterColor *color)
16484 {
16485   ClutterActorPrivate *priv = self->priv;
16486   GObject *obj;
16487
16488   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16489     return;
16490
16491   obj = G_OBJECT (self);
16492
16493   priv->bg_color = *color;
16494   priv->bg_color_set = TRUE;
16495
16496   clutter_actor_queue_redraw (self);
16497
16498   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16499   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16500 }
16501
16502 /**
16503  * clutter_actor_set_background_color:
16504  * @self: a #ClutterActor
16505  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16506  *  set color
16507  *
16508  * Sets the background color of a #ClutterActor.
16509  *
16510  * The background color will be used to cover the whole allocation of the
16511  * actor. The default background color of an actor is transparent.
16512  *
16513  * To check whether an actor has a background color, you can use the
16514  * #ClutterActor:background-color-set actor property.
16515  *
16516  * The #ClutterActor:background-color property is animatable.
16517  *
16518  * Since: 1.10
16519  */
16520 void
16521 clutter_actor_set_background_color (ClutterActor       *self,
16522                                     const ClutterColor *color)
16523 {
16524   ClutterActorPrivate *priv;
16525   GObject *obj;
16526   GParamSpec *bg_color_pspec;
16527
16528   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16529
16530   obj = G_OBJECT (self);
16531
16532   priv = self->priv;
16533
16534   if (color == NULL)
16535     {
16536       priv->bg_color_set = FALSE;
16537       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16538       clutter_actor_queue_redraw (self);
16539       return;
16540     }
16541
16542   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16543   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16544     {
16545       _clutter_actor_create_transition (self, bg_color_pspec,
16546                                         &priv->bg_color,
16547                                         color);
16548     }
16549   else
16550     _clutter_actor_update_transition (self, bg_color_pspec, color);
16551
16552   clutter_actor_queue_redraw (self);
16553 }
16554
16555 /**
16556  * clutter_actor_get_background_color:
16557  * @self: a #ClutterActor
16558  * @color: (out caller-allocates): return location for a #ClutterColor
16559  *
16560  * Retrieves the color set using clutter_actor_set_background_color().
16561  *
16562  * Since: 1.10
16563  */
16564 void
16565 clutter_actor_get_background_color (ClutterActor *self,
16566                                     ClutterColor *color)
16567 {
16568   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16569   g_return_if_fail (color != NULL);
16570
16571   *color = self->priv->bg_color;
16572 }
16573
16574 /**
16575  * clutter_actor_get_previous_sibling:
16576  * @self: a #ClutterActor
16577  *
16578  * Retrieves the sibling of @self that comes before it in the list
16579  * of children of @self's parent.
16580  *
16581  * The returned pointer is only valid until the scene graph changes; it
16582  * is not safe to modify the list of children of @self while iterating
16583  * it.
16584  *
16585  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16586  *
16587  * Since: 1.10
16588  */
16589 ClutterActor *
16590 clutter_actor_get_previous_sibling (ClutterActor *self)
16591 {
16592   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16593
16594   return self->priv->prev_sibling;
16595 }
16596
16597 /**
16598  * clutter_actor_get_next_sibling:
16599  * @self: a #ClutterActor
16600  *
16601  * Retrieves the sibling of @self that comes after it in the list
16602  * of children of @self's parent.
16603  *
16604  * The returned pointer is only valid until the scene graph changes; it
16605  * is not safe to modify the list of children of @self while iterating
16606  * it.
16607  *
16608  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16609  *
16610  * Since: 1.10
16611  */
16612 ClutterActor *
16613 clutter_actor_get_next_sibling (ClutterActor *self)
16614 {
16615   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16616
16617   return self->priv->next_sibling;
16618 }
16619
16620 /**
16621  * clutter_actor_get_first_child:
16622  * @self: a #ClutterActor
16623  *
16624  * Retrieves the first child of @self.
16625  *
16626  * The returned pointer is only valid until the scene graph changes; it
16627  * is not safe to modify the list of children of @self while iterating
16628  * it.
16629  *
16630  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16631  *
16632  * Since: 1.10
16633  */
16634 ClutterActor *
16635 clutter_actor_get_first_child (ClutterActor *self)
16636 {
16637   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16638
16639   return self->priv->first_child;
16640 }
16641
16642 /**
16643  * clutter_actor_get_last_child:
16644  * @self: a #ClutterActor
16645  *
16646  * Retrieves the last child of @self.
16647  *
16648  * The returned pointer is only valid until the scene graph changes; it
16649  * is not safe to modify the list of children of @self while iterating
16650  * it.
16651  *
16652  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16653  *
16654  * Since: 1.10
16655  */
16656 ClutterActor *
16657 clutter_actor_get_last_child (ClutterActor *self)
16658 {
16659   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16660
16661   return self->priv->last_child;
16662 }
16663
16664 /* easy way to have properly named fields instead of the dummy ones
16665  * we use in the public structure
16666  */
16667 typedef struct _RealActorIter
16668 {
16669   ClutterActor *root;           /* dummy1 */
16670   ClutterActor *current;        /* dummy2 */
16671   gpointer padding_1;           /* dummy3 */
16672   gint age;                     /* dummy4 */
16673   gpointer padding_2;           /* dummy5 */
16674 } RealActorIter;
16675
16676 /**
16677  * clutter_actor_iter_init:
16678  * @iter: a #ClutterActorIter
16679  * @root: a #ClutterActor
16680  *
16681  * Initializes a #ClutterActorIter, which can then be used to iterate
16682  * efficiently over a section of the scene graph, and associates it
16683  * with @root.
16684  *
16685  * Modifying the scene graph section that contains @root will invalidate
16686  * the iterator.
16687  *
16688  * |[
16689  *   ClutterActorIter iter;
16690  *   ClutterActor *child;
16691  *
16692  *   clutter_actor_iter_init (&iter, container);
16693  *   while (clutter_actor_iter_next (&iter, &child))
16694  *     {
16695  *       /&ast; do something with child &ast;/
16696  *     }
16697  * ]|
16698  *
16699  * Since: 1.10
16700  */
16701 void
16702 clutter_actor_iter_init (ClutterActorIter *iter,
16703                          ClutterActor     *root)
16704 {
16705   RealActorIter *ri = (RealActorIter *) iter;
16706
16707   g_return_if_fail (iter != NULL);
16708   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16709
16710   ri->root = root;
16711   ri->current = NULL;
16712   ri->age = root->priv->age;
16713 }
16714
16715 /**
16716  * clutter_actor_iter_next:
16717  * @iter: a #ClutterActorIter
16718  * @child: (out): return location for a #ClutterActor
16719  *
16720  * Advances the @iter and retrieves the next child of the root #ClutterActor
16721  * that was used to initialize the #ClutterActorIterator.
16722  *
16723  * If the iterator can advance, this function returns %TRUE and sets the
16724  * @child argument.
16725  *
16726  * If the iterator cannot advance, this function returns %FALSE, and
16727  * the contents of @child are undefined.
16728  *
16729  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16730  *
16731  * Since: 1.10
16732  */
16733 gboolean
16734 clutter_actor_iter_next (ClutterActorIter  *iter,
16735                          ClutterActor     **child)
16736 {
16737   RealActorIter *ri = (RealActorIter *) iter;
16738
16739   g_return_val_if_fail (iter != NULL, FALSE);
16740   g_return_val_if_fail (ri->root != NULL, FALSE);
16741 #ifndef G_DISABLE_ASSERT
16742   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16743 #endif
16744
16745   if (ri->current == NULL)
16746     ri->current = ri->root->priv->first_child;
16747   else
16748     ri->current = ri->current->priv->next_sibling;
16749
16750   if (child != NULL)
16751     *child = ri->current;
16752
16753   return ri->current != NULL;
16754 }
16755
16756 /**
16757  * clutter_actor_iter_prev:
16758  * @iter: a #ClutterActorIter
16759  * @child: (out): return location for a #ClutterActor
16760  *
16761  * Advances the @iter and retrieves the previous child of the root
16762  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16763  *
16764  * If the iterator can advance, this function returns %TRUE and sets the
16765  * @child argument.
16766  *
16767  * If the iterator cannot advance, this function returns %FALSE, and
16768  * the contents of @child are undefined.
16769  *
16770  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16771  *
16772  * Since: 1.10
16773  */
16774 gboolean
16775 clutter_actor_iter_prev (ClutterActorIter  *iter,
16776                          ClutterActor     **child)
16777 {
16778   RealActorIter *ri = (RealActorIter *) iter;
16779
16780   g_return_val_if_fail (iter != NULL, FALSE);
16781   g_return_val_if_fail (ri->root != NULL, FALSE);
16782 #ifndef G_DISABLE_ASSERT
16783   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16784 #endif
16785
16786   if (ri->current == NULL)
16787     ri->current = ri->root->priv->last_child;
16788   else
16789     ri->current = ri->current->priv->prev_sibling;
16790
16791   if (child != NULL)
16792     *child = ri->current;
16793
16794   return ri->current != NULL;
16795 }
16796
16797 /**
16798  * clutter_actor_iter_remove:
16799  * @iter: a #ClutterActorIter
16800  *
16801  * Safely removes the #ClutterActor currently pointer to by the iterator
16802  * from its parent.
16803  *
16804  * This function can only be called after clutter_actor_iter_next() or
16805  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16806  * than once for the same actor.
16807  *
16808  * This function will call clutter_actor_remove_child() internally.
16809  *
16810  * Since: 1.10
16811  */
16812 void
16813 clutter_actor_iter_remove (ClutterActorIter *iter)
16814 {
16815   RealActorIter *ri = (RealActorIter *) iter;
16816   ClutterActor *cur;
16817
16818   g_return_if_fail (iter != NULL);
16819   g_return_if_fail (ri->root != NULL);
16820 #ifndef G_DISABLE_ASSERT
16821   g_return_if_fail (ri->age == ri->root->priv->age);
16822 #endif
16823   g_return_if_fail (ri->current != NULL);
16824
16825   cur = ri->current;
16826
16827   if (cur != NULL)
16828     {
16829       ri->current = cur->priv->prev_sibling;
16830
16831       clutter_actor_remove_child_internal (ri->root, cur,
16832                                            REMOVE_CHILD_DEFAULT_FLAGS);
16833
16834       ri->age += 1;
16835     }
16836 }
16837
16838 /**
16839  * clutter_actor_iter_destroy:
16840  * @iter: a #ClutterActorIter
16841  *
16842  * Safely destroys the #ClutterActor currently pointer to by the iterator
16843  * from its parent.
16844  *
16845  * This function can only be called after clutter_actor_iter_next() or
16846  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16847  * than once for the same actor.
16848  *
16849  * This function will call clutter_actor_destroy() internally.
16850  *
16851  * Since: 1.10
16852  */
16853 void
16854 clutter_actor_iter_destroy (ClutterActorIter *iter)
16855 {
16856   RealActorIter *ri = (RealActorIter *) iter;
16857   ClutterActor *cur;
16858
16859   g_return_if_fail (iter != NULL);
16860   g_return_if_fail (ri->root != NULL);
16861 #ifndef G_DISABLE_ASSERT
16862   g_return_if_fail (ri->age == ri->root->priv->age);
16863 #endif
16864   g_return_if_fail (ri->current != NULL);
16865
16866   cur = ri->current;
16867
16868   if (cur != NULL)
16869     {
16870       ri->current = cur->priv->prev_sibling;
16871
16872       clutter_actor_destroy (cur);
16873
16874       ri->age += 1;
16875     }
16876 }
16877
16878 static const ClutterAnimationInfo default_animation_info = {
16879   NULL,         /* transitions */
16880   NULL,         /* states */
16881   NULL,         /* cur_state */
16882 };
16883
16884 static void
16885 clutter_animation_info_free (gpointer data)
16886 {
16887   if (data != NULL)
16888     {
16889       ClutterAnimationInfo *info = data;
16890
16891       if (info->transitions != NULL)
16892         g_hash_table_unref (info->transitions);
16893
16894       if (info->states != NULL)
16895         g_array_unref (info->states);
16896
16897       g_slice_free (ClutterAnimationInfo, info);
16898     }
16899 }
16900
16901 const ClutterAnimationInfo *
16902 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16903 {
16904   const ClutterAnimationInfo *res;
16905   GObject *obj = G_OBJECT (self);
16906
16907   res = g_object_get_qdata (obj, quark_actor_animation_info);
16908   if (res != NULL)
16909     return res;
16910
16911   return &default_animation_info;
16912 }
16913
16914 ClutterAnimationInfo *
16915 _clutter_actor_get_animation_info (ClutterActor *self)
16916 {
16917   GObject *obj = G_OBJECT (self);
16918   ClutterAnimationInfo *res;
16919
16920   res = g_object_get_qdata (obj, quark_actor_animation_info);
16921   if (res == NULL)
16922     {
16923       res = g_slice_new (ClutterAnimationInfo);
16924
16925       *res = default_animation_info;
16926
16927       g_object_set_qdata_full (obj, quark_actor_animation_info,
16928                                res,
16929                                clutter_animation_info_free);
16930     }
16931
16932   return res;
16933 }
16934
16935 ClutterTransition *
16936 _clutter_actor_get_transition (ClutterActor *actor,
16937                                GParamSpec   *pspec)
16938 {
16939   const ClutterAnimationInfo *info;
16940
16941   info = _clutter_actor_get_animation_info_or_defaults (actor);
16942
16943   if (info->transitions == NULL)
16944     return NULL;
16945
16946   return g_hash_table_lookup (info->transitions, pspec->name);
16947 }
16948
16949 typedef struct _TransitionClosure
16950 {
16951   ClutterActor *actor;
16952   ClutterTransition *transition;
16953   gchar *name;
16954   gulong completed_id;
16955 } TransitionClosure;
16956
16957 static void
16958 transition_closure_free (gpointer data)
16959 {
16960   if (G_LIKELY (data != NULL))
16961     {
16962       TransitionClosure *clos = data;
16963       ClutterTimeline *timeline;
16964
16965       timeline = CLUTTER_TIMELINE (clos->transition);
16966
16967       if (clutter_timeline_is_playing (timeline))
16968         clutter_timeline_stop (timeline);
16969
16970       g_signal_handler_disconnect (clos->transition, clos->completed_id);
16971
16972       g_object_unref (clos->transition);
16973       g_free (clos->name);
16974
16975       g_slice_free (TransitionClosure, clos);
16976     }
16977 }
16978
16979 static void
16980 on_transition_completed (ClutterTransition *transition,
16981                          TransitionClosure *clos)
16982 {
16983   ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
16984   ClutterActor *actor = clos->actor;
16985   ClutterAnimationInfo *info;
16986   gint n_repeats, cur_repeat;
16987
16988   info = _clutter_actor_get_animation_info (actor);
16989
16990   /* reset the caches used by animations */
16991   clutter_actor_store_content_box (actor, NULL);
16992
16993   /* ensure that we remove the transition only at the end
16994    * of its run; we emit ::completed for every repeat
16995    */
16996   n_repeats = clutter_timeline_get_repeat_count (timeline);
16997   cur_repeat = clutter_timeline_get_current_repeat (timeline);
16998
16999   if (cur_repeat == n_repeats)
17000     {
17001       if (clutter_transition_get_remove_on_complete (transition))
17002         {
17003           /* we take a reference here because removing the closure
17004            * will release the reference on the transition, and we
17005            * want the transition to survive the signal emission;
17006            * the master clock will release the last reference at
17007            * the end of the frame processing.
17008            */
17009           g_object_ref (transition);
17010           g_hash_table_remove (info->transitions, clos->name);
17011         }
17012     }
17013
17014   /* if it's the last transition then we clean up */
17015   if (g_hash_table_size (info->transitions) == 0)
17016     {
17017       g_hash_table_unref (info->transitions);
17018       info->transitions = NULL;
17019
17020       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17021                     _clutter_actor_get_debug_name (actor));
17022
17023       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17024     }
17025 }
17026
17027 void
17028 _clutter_actor_update_transition (ClutterActor *actor,
17029                                   GParamSpec   *pspec,
17030                                   ...)
17031 {
17032   TransitionClosure *clos;
17033   ClutterTimeline *timeline;
17034   ClutterInterval *interval;
17035   const ClutterAnimationInfo *info;
17036   va_list var_args;
17037   GType ptype;
17038   GValue initial = G_VALUE_INIT;
17039   GValue final = G_VALUE_INIT;
17040   char *error = NULL;
17041
17042   info = _clutter_actor_get_animation_info_or_defaults (actor);
17043
17044   if (info->transitions == NULL)
17045     return;
17046
17047   clos = g_hash_table_lookup (info->transitions, pspec->name);
17048   if (clos == NULL)
17049     return;
17050
17051   timeline = CLUTTER_TIMELINE (clos->transition);
17052
17053   va_start (var_args, pspec);
17054
17055   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17056
17057   g_value_init (&initial, ptype);
17058   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17059                                         pspec->name,
17060                                         &initial);
17061
17062   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17063   if (error != NULL)
17064     {
17065       g_critical ("%s: %s", G_STRLOC, error);
17066       g_free (error);
17067       goto out;
17068     }
17069
17070   interval = clutter_transition_get_interval (clos->transition);
17071   clutter_interval_set_initial_value (interval, &initial);
17072   clutter_interval_set_final_value (interval, &final);
17073
17074   /* if we're updating with an easing duration of zero milliseconds,
17075    * we just jump the timeline to the end and let it run its course
17076    */
17077   if (info->cur_state != NULL &&
17078       info->cur_state->easing_duration != 0)
17079     {
17080       guint cur_duration = clutter_timeline_get_duration (timeline);
17081       ClutterAnimationMode cur_mode =
17082         clutter_timeline_get_progress_mode (timeline);
17083
17084       if (cur_duration != info->cur_state->easing_duration)
17085         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17086
17087       if (cur_mode != info->cur_state->easing_mode)
17088         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17089
17090       clutter_timeline_rewind (timeline);
17091     }
17092   else
17093     {
17094       guint duration = clutter_timeline_get_duration (timeline);
17095
17096       clutter_timeline_advance (timeline, duration);
17097     }
17098
17099 out:
17100   g_value_unset (&initial);
17101   g_value_unset (&final);
17102
17103   va_end (var_args);
17104 }
17105
17106 /*< private >*
17107  * _clutter_actor_create_transition:
17108  * @actor: a #ClutterActor
17109  * @pspec: the property used for the transition
17110  * @...: initial and final state
17111  *
17112  * Creates a #ClutterTransition for the property represented by @pspec.
17113  *
17114  * Return value: a #ClutterTransition
17115  */
17116 ClutterTransition *
17117 _clutter_actor_create_transition (ClutterActor *actor,
17118                                   GParamSpec   *pspec,
17119                                   ...)
17120 {
17121   ClutterAnimationInfo *info;
17122   ClutterTransition *res = NULL;
17123   gboolean call_restore = FALSE;
17124   TransitionClosure *clos;
17125   va_list var_args;
17126
17127   info = _clutter_actor_get_animation_info (actor);
17128
17129   /* XXX - this will go away in 2.0
17130    *
17131    * if no state has been pushed, we assume that the easing state is
17132    * in "compatibility mode": all transitions have a duration of 0
17133    * msecs, which means that they happen immediately. in Clutter 2.0
17134    * this will turn into a g_assert(info->states != NULL), as every
17135    * actor will start with a predefined easing state
17136    */
17137   if (info->states == NULL)
17138     {
17139       clutter_actor_save_easing_state (actor);
17140       clutter_actor_set_easing_duration (actor, 0);
17141       call_restore = TRUE;
17142     }
17143
17144   if (info->transitions == NULL)
17145     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17146                                                NULL,
17147                                                transition_closure_free);
17148
17149   va_start (var_args, pspec);
17150
17151   clos = g_hash_table_lookup (info->transitions, pspec->name);
17152   if (clos == NULL)
17153     {
17154       ClutterTimeline *timeline;
17155       ClutterInterval *interval;
17156       GValue initial = G_VALUE_INIT;
17157       GValue final = G_VALUE_INIT;
17158       GType ptype;
17159       char *error;
17160
17161       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17162
17163       G_VALUE_COLLECT_INIT (&initial, ptype,
17164                             var_args, 0,
17165                             &error);
17166       if (error != NULL)
17167         {
17168           g_critical ("%s: %s", G_STRLOC, error);
17169           g_free (error);
17170           goto out;
17171         }
17172
17173       G_VALUE_COLLECT_INIT (&final, ptype,
17174                             var_args, 0,
17175                             &error);
17176
17177       if (error != NULL)
17178         {
17179           g_critical ("%s: %s", G_STRLOC, error);
17180           g_value_unset (&initial);
17181           g_free (error);
17182           goto out;
17183         }
17184
17185       /* if the current easing state has a duration of 0, then we don't
17186        * bother to create the transition, and we just set the final value
17187        * directly on the actor; we don't go through the Animatable
17188        * interface because we know we got here through an animatable
17189        * property.
17190        */
17191       if (info->cur_state->easing_duration == 0)
17192         {
17193           clutter_actor_set_animatable_property (actor,
17194                                                  pspec->param_id,
17195                                                  &final,
17196                                                  pspec);
17197           g_value_unset (&initial);
17198           g_value_unset (&final);
17199
17200           goto out;
17201         }
17202
17203       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17204
17205       g_value_unset (&initial);
17206       g_value_unset (&final);
17207
17208       res = clutter_property_transition_new (pspec->name);
17209
17210       clutter_transition_set_interval (res, interval);
17211       clutter_transition_set_remove_on_complete (res, TRUE);
17212
17213       timeline = CLUTTER_TIMELINE (res);
17214       clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17215       clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17216       clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17217
17218       /* this will start the transition as well */
17219       clutter_actor_add_transition (actor, pspec->name, res);
17220
17221       /* the actor now owns the transition */
17222       g_object_unref (res);
17223     }
17224   else
17225     res = clos->transition;
17226
17227 out:
17228   if (call_restore)
17229     clutter_actor_restore_easing_state (actor);
17230
17231   va_end (var_args);
17232
17233   return res;
17234 }
17235
17236 /**
17237  * clutter_actor_add_transition:
17238  * @self: a #ClutterActor
17239  * @name: the name of the transition to add
17240  * @transition: the #ClutterTransition to add
17241  *
17242  * Adds a @transition to the #ClutterActor's list of animations.
17243  *
17244  * The @name string is a per-actor unique identifier of the @transition: only
17245  * one #ClutterTransition can be associated to the specified @name.
17246  *
17247  * The @transition will be given the easing duration, mode, and delay
17248  * associated to the actor's current easing state; it is possible to modify
17249  * these values after calling clutter_actor_add_transition().
17250  *
17251  * The @transition will be started once added.
17252  *
17253  * This function will take a reference on the @transition.
17254  *
17255  * This function is usually called implicitly when modifying an animatable
17256  * property.
17257  *
17258  * Since: 1.10
17259  */
17260 void
17261 clutter_actor_add_transition (ClutterActor      *self,
17262                               const char        *name,
17263                               ClutterTransition *transition)
17264 {
17265   ClutterTimeline *timeline;
17266   TransitionClosure *clos;
17267   ClutterAnimationInfo *info;
17268
17269   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17270   g_return_if_fail (name != NULL);
17271   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17272
17273   info = _clutter_actor_get_animation_info (self);
17274
17275   if (info->transitions == NULL)
17276     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17277                                                NULL,
17278                                                transition_closure_free);
17279
17280   if (g_hash_table_lookup (info->transitions, name) != NULL)
17281     {
17282       g_warning ("A transition with name '%s' already exists for "
17283                  "the actor '%s'",
17284                  name,
17285                  _clutter_actor_get_debug_name (self));
17286       return;
17287     }
17288
17289   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17290
17291   timeline = CLUTTER_TIMELINE (transition);
17292
17293   if (info->cur_state != NULL)
17294     {
17295       clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17296       clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17297       clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17298     }
17299
17300   clos = g_slice_new (TransitionClosure);
17301   clos->actor = self;
17302   clos->transition = g_object_ref (transition);
17303   clos->name = g_strdup (name);
17304   clos->completed_id = g_signal_connect (timeline, "completed",
17305                                          G_CALLBACK (on_transition_completed),
17306                                          clos);
17307
17308   CLUTTER_NOTE (ANIMATION,
17309                 "Adding transition '%s' [%p] to actor '%s'",
17310                 clos->name,
17311                 clos->transition,
17312                 _clutter_actor_get_debug_name (self));
17313
17314   g_hash_table_insert (info->transitions, clos->name, clos);
17315   clutter_timeline_start (timeline);
17316 }
17317
17318 /**
17319  * clutter_actor_remove_transition:
17320  * @self: a #ClutterActor
17321  * @name: the name of the transition to remove
17322  *
17323  * Removes the transition stored inside a #ClutterActor using @name
17324  * identifier.
17325  *
17326  * If the transition is currently in progress, it will be stopped.
17327  *
17328  * This function releases the reference acquired when the transition
17329  * was added to the #ClutterActor.
17330  *
17331  * Since: 1.10
17332  */
17333 void
17334 clutter_actor_remove_transition (ClutterActor *self,
17335                                  const char   *name)
17336 {
17337   const ClutterAnimationInfo *info;
17338
17339   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17340   g_return_if_fail (name != NULL);
17341
17342   info = _clutter_actor_get_animation_info_or_defaults (self);
17343
17344   if (info->transitions == NULL)
17345     return;
17346
17347   g_hash_table_remove (info->transitions, name);
17348 }
17349
17350 /**
17351  * clutter_actor_remove_all_transitions:
17352  * @self: a #ClutterActor
17353  *
17354  * Removes all transitions associated to @self.
17355  *
17356  * Since: 1.10
17357  */
17358 void
17359 clutter_actor_remove_all_transitions (ClutterActor *self)
17360 {
17361   const ClutterAnimationInfo *info;
17362
17363   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17364
17365   info = _clutter_actor_get_animation_info_or_defaults (self);
17366   if (info->transitions == NULL)
17367     return;
17368
17369   g_hash_table_remove_all (info->transitions);
17370 }
17371
17372 /**
17373  * clutter_actor_set_easing_duration:
17374  * @self: a #ClutterActor
17375  * @msecs: the duration of the easing, or %NULL
17376  *
17377  * Sets the duration of the tweening for animatable properties
17378  * of @self for the current easing state.
17379  *
17380  * Since: 1.10
17381  */
17382 void
17383 clutter_actor_set_easing_duration (ClutterActor *self,
17384                                    guint         msecs)
17385 {
17386   ClutterAnimationInfo *info;
17387
17388   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17389
17390   info = _clutter_actor_get_animation_info (self);
17391
17392   if (info->cur_state == NULL)
17393     {
17394       g_warning ("You must call clutter_actor_save_easing_state() prior "
17395                  "to calling clutter_actor_set_easing_duration().");
17396       return;
17397     }
17398
17399   if (info->cur_state->easing_duration != msecs)
17400     info->cur_state->easing_duration = msecs;
17401 }
17402
17403 /**
17404  * clutter_actor_get_easing_duration:
17405  * @self: a #ClutterActor
17406  *
17407  * Retrieves the duration of the tweening for animatable
17408  * properties of @self for the current easing state.
17409  *
17410  * Return value: the duration of the tweening, in milliseconds
17411  *
17412  * Since: 1.10
17413  */
17414 guint
17415 clutter_actor_get_easing_duration (ClutterActor *self)
17416 {
17417   const ClutterAnimationInfo *info;
17418
17419   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17420
17421   info = _clutter_actor_get_animation_info_or_defaults (self);
17422
17423   if (info->cur_state != NULL)
17424     return info->cur_state->easing_duration;
17425
17426   return 0;
17427 }
17428
17429 /**
17430  * clutter_actor_set_easing_mode:
17431  * @self: a #ClutterActor
17432  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17433  *
17434  * Sets the easing mode for the tweening of animatable properties
17435  * of @self.
17436  *
17437  * Since: 1.10
17438  */
17439 void
17440 clutter_actor_set_easing_mode (ClutterActor         *self,
17441                                ClutterAnimationMode  mode)
17442 {
17443   ClutterAnimationInfo *info;
17444
17445   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17446   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17447   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17448
17449   info = _clutter_actor_get_animation_info (self);
17450
17451   if (info->cur_state == NULL)
17452     {
17453       g_warning ("You must call clutter_actor_save_easing_state() prior "
17454                  "to calling clutter_actor_set_easing_mode().");
17455       return;
17456     }
17457
17458   if (info->cur_state->easing_mode != mode)
17459     info->cur_state->easing_mode = mode;
17460 }
17461
17462 /**
17463  * clutter_actor_get_easing_mode:
17464  * @self: a #ClutterActor
17465  *
17466  * Retrieves the easing mode for the tweening of animatable properties
17467  * of @self for the current easing state.
17468  *
17469  * Return value: an easing mode
17470  *
17471  * Since: 1.10
17472  */
17473 ClutterAnimationMode
17474 clutter_actor_get_easing_mode (ClutterActor *self)
17475 {
17476   const ClutterAnimationInfo *info;
17477
17478   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17479
17480   info = _clutter_actor_get_animation_info_or_defaults (self);
17481
17482   if (info->cur_state != NULL)
17483     return info->cur_state->easing_mode;
17484
17485   return CLUTTER_EASE_OUT_CUBIC;
17486 }
17487
17488 /**
17489  * clutter_actor_set_easing_delay:
17490  * @self: a #ClutterActor
17491  * @msecs: the delay before the start of the tweening, in milliseconds
17492  *
17493  * Sets the delay that should be applied before tweening animatable
17494  * properties.
17495  *
17496  * Since: 1.10
17497  */
17498 void
17499 clutter_actor_set_easing_delay (ClutterActor *self,
17500                                 guint         msecs)
17501 {
17502   ClutterAnimationInfo *info;
17503
17504   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17505
17506   info = _clutter_actor_get_animation_info (self);
17507
17508   if (info->cur_state == NULL)
17509     {
17510       g_warning ("You must call clutter_actor_save_easing_state() prior "
17511                  "to calling clutter_actor_set_easing_delay().");
17512       return;
17513     }
17514
17515   if (info->cur_state->easing_delay != msecs)
17516     info->cur_state->easing_delay = msecs;
17517 }
17518
17519 /**
17520  * clutter_actor_get_easing_delay:
17521  * @self: a #ClutterActor
17522  *
17523  * Retrieves the delay that should be applied when tweening animatable
17524  * properties.
17525  *
17526  * Return value: a delay, in milliseconds
17527  *
17528  * Since: 1.10
17529  */
17530 guint
17531 clutter_actor_get_easing_delay (ClutterActor *self)
17532 {
17533   const ClutterAnimationInfo *info;
17534
17535   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17536
17537   info = _clutter_actor_get_animation_info_or_defaults (self);
17538
17539   if (info->cur_state != NULL)
17540     return info->cur_state->easing_delay;
17541
17542   return 0;
17543 }
17544
17545 /**
17546  * clutter_actor_get_transition:
17547  * @self: a #ClutterActor
17548  * @name: the name of the transition
17549  *
17550  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17551  * transition @name.
17552  *
17553  * Transitions created for animatable properties use the name of the
17554  * property itself, for instance the code below:
17555  *
17556  * |[
17557  *   clutter_actor_set_easing_duration (actor, 1000);
17558  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17559  *
17560  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17561  *   g_signal_connect (transition, "completed",
17562  *                     G_CALLBACK (on_transition_complete),
17563  *                     actor);
17564  * ]|
17565  *
17566  * will call the <function>on_transition_complete</function> callback when
17567  * the transition is complete.
17568  *
17569  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17570  *   was found to match the passed name; the returned instance is owned
17571  *   by Clutter and it should not be freed
17572  *
17573  * Since: 1.10
17574  */
17575 ClutterTransition *
17576 clutter_actor_get_transition (ClutterActor *self,
17577                               const char   *name)
17578 {
17579   TransitionClosure *clos;
17580   const ClutterAnimationInfo *info;
17581
17582   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17583   g_return_val_if_fail (name != NULL, NULL);
17584
17585   info = _clutter_actor_get_animation_info_or_defaults (self);
17586   if (info->transitions == NULL)
17587     return NULL;
17588
17589   clos = g_hash_table_lookup (info->transitions, name);
17590   if (clos == NULL)
17591     return NULL;
17592
17593   return clos->transition;
17594 }
17595
17596 /**
17597  * clutter_actor_save_easing_state:
17598  * @self: a #ClutterActor
17599  *
17600  * Saves the current easing state for animatable properties, and creates
17601  * a new state with the default values for easing mode and duration.
17602  *
17603  * Since: 1.10
17604  */
17605 void
17606 clutter_actor_save_easing_state (ClutterActor *self)
17607 {
17608   ClutterAnimationInfo *info;
17609   AState new_state;
17610
17611   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17612
17613   info = _clutter_actor_get_animation_info (self);
17614
17615   if (info->states == NULL)
17616     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17617
17618   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17619   new_state.easing_duration = 250;
17620   new_state.easing_delay = 0;
17621
17622   g_array_append_val (info->states, new_state);
17623
17624   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17625 }
17626
17627 /**
17628  * clutter_actor_restore_easing_state:
17629  * @self: a #ClutterActor
17630  *
17631  * Restores the easing state as it was prior to a call to
17632  * clutter_actor_save_easing_state().
17633  *
17634  * Since: 1.10
17635  */
17636 void
17637 clutter_actor_restore_easing_state (ClutterActor *self)
17638 {
17639   ClutterAnimationInfo *info;
17640
17641   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17642
17643   info = _clutter_actor_get_animation_info (self);
17644
17645   if (info->states == NULL)
17646     {
17647       g_critical ("The function clutter_actor_restore_easing_state() has "
17648                   "called without a previous call to "
17649                   "clutter_actor_save_easing_state().");
17650       return;
17651     }
17652
17653   g_array_remove_index (info->states, info->states->len - 1);
17654
17655   if (info->states->len > 0)
17656     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17657   else
17658     {
17659       g_array_unref (info->states);
17660       info->states = NULL;
17661       info->cur_state = NULL;
17662     }
17663 }
17664
17665 /**
17666  * clutter_actor_set_content:
17667  * @self: a #ClutterActor
17668  * @content: (allow-none): a #ClutterContent, or %NULL
17669  *
17670  * Sets the contents of a #ClutterActor.
17671  *
17672  * Since: 1.10
17673  */
17674 void
17675 clutter_actor_set_content (ClutterActor   *self,
17676                            ClutterContent *content)
17677 {
17678   ClutterActorPrivate *priv;
17679
17680   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17681   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17682
17683   priv = self->priv;
17684
17685   if (priv->content != NULL)
17686     {
17687       _clutter_content_detached (priv->content, self);
17688       g_clear_object (&priv->content);
17689     }
17690
17691   priv->content = content;
17692
17693   if (priv->content != NULL)
17694     {
17695       g_object_ref (priv->content);
17696       _clutter_content_attached (priv->content, self);
17697     }
17698
17699   /* given that the content is always painted within the allocation,
17700    * we only need to queue a redraw here
17701    */
17702   clutter_actor_queue_redraw (self);
17703
17704   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17705
17706   /* if the content gravity is not resize-fill, and the new content has a
17707    * different preferred size than the previous one, then the content box
17708    * may have been changed. since we compute that lazily, we just notify
17709    * here, and let whomever watches :content-box do whatever they need to
17710    * do.
17711    */
17712   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17713     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17714 }
17715
17716 /**
17717  * clutter_actor_get_content:
17718  * @self: a #ClutterActor
17719  *
17720  * Retrieves the contents of @self.
17721  *
17722  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17723  *   or %NULL if none was set
17724  *
17725  * Since: 1.10
17726  */
17727 ClutterContent *
17728 clutter_actor_get_content (ClutterActor *self)
17729 {
17730   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17731
17732   return self->priv->content;
17733 }
17734
17735 /**
17736  * clutter_actor_set_content_gravity:
17737  * @self: a #ClutterActor
17738  * @gravity: the #ClutterContentGravity
17739  *
17740  * Sets the gravity of the #ClutterContent used by @self.
17741  *
17742  * See the description of the #ClutterActor:content-gravity property for
17743  * more information.
17744  *
17745  * The #ClutterActor:content-gravity property is animatable.
17746  *
17747  * Since: 1.10
17748  */
17749 void
17750 clutter_actor_set_content_gravity (ClutterActor *self,
17751                                    ClutterContentGravity  gravity)
17752 {
17753   ClutterActorPrivate *priv;
17754
17755   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17756
17757   priv = self->priv;
17758
17759   if (priv->content_gravity == gravity)
17760     return;
17761
17762   priv->content_box_valid = FALSE;
17763
17764   if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17765     {
17766       ClutterActorBox from_box, to_box;
17767
17768       clutter_actor_get_content_box (self, &from_box);
17769
17770       priv->content_gravity = gravity;
17771
17772       clutter_actor_get_content_box (self, &to_box);
17773
17774       _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17775                                         &from_box,
17776                                         &to_box);
17777     }
17778   else
17779     {
17780       ClutterActorBox to_box;
17781
17782       priv->content_gravity = gravity;
17783
17784       clutter_actor_get_content_box (self, &to_box);
17785
17786       _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17787                                         &to_box);
17788     }
17789
17790   clutter_actor_queue_redraw (self);
17791
17792   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17793 }
17794
17795 /**
17796  * clutter_actor_get_content_gravity:
17797  * @self: a #ClutterActor
17798  *
17799  * Retrieves the content gravity as set using
17800  * clutter_actor_get_content_gravity().
17801  *
17802  * Return value: the content gravity
17803  *
17804  * Since: 1.10
17805  */
17806 ClutterContentGravity
17807 clutter_actor_get_content_gravity (ClutterActor *self)
17808 {
17809   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17810                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17811
17812   return self->priv->content_gravity;
17813 }
17814
17815 /**
17816  * clutter_actor_get_content_box:
17817  * @self: a #ClutterActor
17818  * @box: (out caller-allocates): the return location for the bounding
17819  *   box for the #ClutterContent
17820  *
17821  * Retrieves the bounding box for the #ClutterContent of @self.
17822  *
17823  * The bounding box is relative to the actor's allocation.
17824  *
17825  * If no #ClutterContent is set for @self, or if @self has not been
17826  * allocated yet, then the result is undefined.
17827  *
17828  * The content box is guaranteed to be, at most, as big as the allocation
17829  * of the #ClutterActor.
17830  *
17831  * If the #ClutterContent used by the actor has a preferred size, then
17832  * it is possible to modify the content box by using the
17833  * #ClutterActor:content-gravity property.
17834  *
17835  * Since: 1.10
17836  */
17837 void
17838 clutter_actor_get_content_box (ClutterActor    *self,
17839                                ClutterActorBox *box)
17840 {
17841   ClutterActorPrivate *priv;
17842   gfloat content_w, content_h;
17843   gfloat alloc_w, alloc_h;
17844
17845   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17846   g_return_if_fail (box != NULL);
17847
17848   priv = self->priv;
17849
17850   box->x1 = 0.f;
17851   box->y1 = 0.f;
17852   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17853   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17854
17855   if (priv->content_box_valid)
17856     {
17857       *box = priv->content_box;
17858       return;
17859     }
17860
17861   /* no need to do any more work */
17862   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17863     return;
17864
17865   if (priv->content == NULL)
17866     return;
17867
17868   /* if the content does not have a preferred size then there is
17869    * no point in computing the content box
17870    */
17871   if (!clutter_content_get_preferred_size (priv->content,
17872                                            &content_w,
17873                                            &content_h))
17874     return;
17875
17876   alloc_w = box->x2;
17877   alloc_h = box->y2;
17878
17879   switch (priv->content_gravity)
17880     {
17881     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17882       box->x2 = box->x1 + MIN (content_w, alloc_w);
17883       box->y2 = box->y1 + MIN (content_h, alloc_h);
17884       break;
17885
17886     case CLUTTER_CONTENT_GRAVITY_TOP:
17887       if (alloc_w > content_w)
17888         {
17889           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17890           box->x2 = box->x1 + content_w;
17891         }
17892       box->y2 = box->y1 + MIN (content_h, alloc_h);
17893       break;
17894
17895     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17896       if (alloc_w > content_w)
17897         {
17898           box->x1 += (alloc_w - content_w);
17899           box->x2 = box->x1 + content_w;
17900         }
17901       box->y2 = box->y1 + MIN (content_h, alloc_h);
17902       break;
17903
17904     case CLUTTER_CONTENT_GRAVITY_LEFT:
17905       box->x2 = box->x1 + MIN (content_w, alloc_w);
17906       if (alloc_h > content_h)
17907         {
17908           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17909           box->y2 = box->y1 + content_h;
17910         }
17911       break;
17912
17913     case CLUTTER_CONTENT_GRAVITY_CENTER:
17914       if (alloc_w > content_w)
17915         {
17916           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17917           box->x2 = box->x1 + content_w;
17918         }
17919       if (alloc_h > content_h)
17920         {
17921           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17922           box->y2 = box->y1 + content_h;
17923         }
17924       break;
17925
17926     case CLUTTER_CONTENT_GRAVITY_RIGHT:
17927       if (alloc_w > content_w)
17928         {
17929           box->x1 += (alloc_w - content_w);
17930           box->x2 = box->x1 + content_w;
17931         }
17932       if (alloc_h > content_h)
17933         {
17934           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17935           box->y2 = box->y1 + content_h;
17936         }
17937       break;
17938
17939     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17940       box->x2 = box->x1 + MIN (content_w, alloc_w);
17941       if (alloc_h > content_h)
17942         {
17943           box->y1 += (alloc_h - content_h);
17944           box->y2 = box->y1 + content_h;
17945         }
17946       break;
17947
17948     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17949       if (alloc_w > content_w)
17950         {
17951           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17952           box->x2 = box->x1 + content_w;
17953         }
17954       if (alloc_h > content_h)
17955         {
17956           box->y1 += (alloc_h - content_h);
17957           box->y2 = box->y1 + content_h;
17958         }
17959       break;
17960
17961     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17962       if (alloc_w > content_w)
17963         {
17964           box->x1 += (alloc_w - content_w);
17965           box->x2 = box->x1 + content_w;
17966         }
17967       if (alloc_h > content_h)
17968         {
17969           box->y1 += (alloc_h - content_h);
17970           box->y2 = box->y1 + content_h;
17971         }
17972       break;
17973
17974     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17975       g_assert_not_reached ();
17976       break;
17977
17978     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17979       {
17980         double r_c = content_w / content_h;
17981         double r_a = alloc_w / alloc_h;
17982
17983         if (r_c >= 1.0)
17984           {
17985             if (r_a >= 1.0)
17986               {
17987                 box->x1 = 0.f;
17988                 box->x2 = alloc_w;
17989
17990                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17991                 box->y2 = box->y1 + (alloc_w * r_c);
17992               }
17993             else
17994               {
17995                 box->y1 = 0.f;
17996                 box->y2 = alloc_h;
17997
17998                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17999                 box->x2 = box->x1 + (alloc_h * r_c);
18000               }
18001           }
18002         else
18003           {
18004             if (r_a >= 1.0)
18005               {
18006                 box->y1 = 0.f;
18007                 box->y2 = alloc_h;
18008
18009                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18010                 box->x2 = box->x1 + (alloc_h * r_c);
18011               }
18012             else
18013               {
18014                 box->x1 = 0.f;
18015                 box->x2 = alloc_w;
18016
18017                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18018                 box->y2 = box->y1 + (alloc_w * r_c);
18019               }
18020           }
18021       }
18022       break;
18023     }
18024 }
18025
18026 /**
18027  * clutter_actor_set_content_scaling_filters:
18028  * @self: a #ClutterActor
18029  * @min_filter: the minification filter for the content
18030  * @mag_filter: the magnification filter for the content
18031  *
18032  * Sets the minification and magnification filter to be applied when
18033  * scaling the #ClutterActor:content of a #ClutterActor.
18034  *
18035  * The #ClutterActor:minification-filter will be used when reducing
18036  * the size of the content; the #ClutterActor:magnification-filter
18037  * will be used when increasing the size of the content.
18038  *
18039  * Since: 1.10
18040  */
18041 void
18042 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18043                                            ClutterScalingFilter  min_filter,
18044                                            ClutterScalingFilter  mag_filter)
18045 {
18046   ClutterActorPrivate *priv;
18047   gboolean changed;
18048   GObject *obj;
18049
18050   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18051
18052   priv = self->priv;
18053   obj = G_OBJECT (self);
18054
18055   g_object_freeze_notify (obj);
18056
18057   changed = FALSE;
18058
18059   if (priv->min_filter != min_filter)
18060     {
18061       priv->min_filter = min_filter;
18062       changed = TRUE;
18063
18064       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18065     }
18066
18067   if (priv->mag_filter != mag_filter)
18068     {
18069       priv->mag_filter = mag_filter;
18070       changed = TRUE;
18071
18072       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18073     }
18074
18075   if (changed)
18076     clutter_actor_queue_redraw (self);
18077
18078   g_object_thaw_notify (obj);
18079 }
18080
18081 /**
18082  * clutter_actor_get_content_scaling_filters:
18083  * @self: a #ClutterActor
18084  * @min_filter: (out) (allow-none): return location for the minification
18085  *   filter, or %NULL
18086  * @mag_filter: (out) (allow-none): return location for the magnification
18087  *   filter, or %NULL
18088  *
18089  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18090  *
18091  * Since: 1.10
18092  */
18093 void
18094 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18095                                            ClutterScalingFilter *min_filter,
18096                                            ClutterScalingFilter *mag_filter)
18097 {
18098   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18099
18100   if (min_filter != NULL)
18101     *min_filter = self->priv->min_filter;
18102
18103   if (mag_filter != NULL)
18104     *mag_filter = self->priv->mag_filter;
18105 }