actor: Not-actors don't have metas
[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_interval (transition, clutter_interval_new (G_TYPE_UINT, 255, 0));
297  *
298  * clutter_actor_add_transition (actor, "animate-opacity", transition);
299  *     </programlisting></informalexample>
300  *     <para>The example above will animate the #ClutterActor:opacity property
301  *     of an actor between fully opaque and fully transparent, and back, over
302  *     a span of 3 seconds. The animation does not begin until it is added to
303  *     the actor.</para>
304  *     <para>The explicit animation API should also be used when using custom
305  *     animatable properties for #ClutterAction, #ClutterConstraint, and
306  *     #ClutterEffect instances associated to an actor; see the section on
307  *     <ulink linkend="ClutterActor-custom-animatable-properties">custom
308  *     animatable properties below</ulink> for an example.</para>
309  *     <para>Finally, explicit animations are useful for creating animations
310  *     that run continuously, for instance:</para>
311  *     <informalexample><programlisting>
312  * /&ast; this animation will pulse the actor's opacity continuously &ast;/
313  * ClutterTransition *transition;
314  * ClutterInterval *interval;
315  *
316  * transition = clutter_property_transition_new ("opacity");
317  *
318  * /&ast; we want to animate the opacity between 0 and 255 &ast;/
319  * internal = clutter_interval_new (G_TYPE_UINT, 0, 255);
320  * clutter_transition_set_interval (transition, interval);
321  *
322  * /&ast; over a one second duration, running an infinite amount of times &ast;/
323  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
324  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
325  *
326  * /&ast; we want to fade in and out, so we need to auto-reverse the transition &ast;/
327  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
328  *
329  * /&ast; and we want to use an easing function that eases both in and out &ast;/
330  * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
331  *                                     CLUTTER_EASE_IN_OUT_CUBIC);
332  *
333  * /&ast; add the transition to the desired actor; this will
334  *  &ast; start the animation.
335  *  &ast;/
336  * clutter_actor_add_transition (actor, "opacityAnimation", transition);
337  *     </programlisting></informalexample>
338  *   </formalpara>
339  * </refsect2>
340  *
341  * <refsect2 id="ClutterActor-subclassing">
342  *   <title>Implementing an actor</title>
343  *   <para>Careful consideration should be given when deciding to implement
344  *   a #ClutterActor sub-class. It is generally recommended to implement a
345  *   sub-class of #ClutterActor only for actors that should be used as leaf
346  *   nodes of a scene graph.</para>
347  *   <para>If your actor should be painted in a custom way, you should
348  *   override the #ClutterActor::paint signal class handler. You can either
349  *   opt to chain up to the parent class implementation or decide to fully
350  *   override the default paint implementation; Clutter will set up the
351  *   transformations and clip regions prior to emitting the #ClutterActor::paint
352  *   signal.</para>
353  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
354  *   #ClutterActorClass.get_preferred_height() virtual functions it is
355  *   possible to change or provide the preferred size of an actor; similarly,
356  *   by overriding the #ClutterActorClass.allocate() virtual function it is
357  *   possible to control the layout of the children of an actor. Make sure to
358  *   always chain up to the parent implementation of the
359  *   #ClutterActorClass.allocate() virtual function.</para>
360  *   <para>In general, it is strongly encouraged to use delegation and
361  *   composition instead of direct subclassing.</para>
362  * </refsect2>
363  *
364  * <refsect2 id="ClutterActor-script">
365  *   <title>ClutterActor custom properties for #ClutterScript</title>
366  *   <para>#ClutterActor defines a custom "rotation" property which
367  *   allows a short-hand description of the rotations to be applied
368  *   to an actor.</para>
369  *   <para>The syntax of the "rotation" property is the following:</para>
370  *   <informalexample>
371  *     <programlisting>
372  * "rotation" : [
373  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
374  * ]
375  *     </programlisting>
376  *   </informalexample>
377  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
378  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
379  *   floating point value representing the rotation angle on the given axis,
380  *   in degrees.</para>
381  *   <para>The <emphasis>center</emphasis> array is optional, and if present
382  *   it must contain the center of rotation as described by two coordinates:
383  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
384  *   "z-axis".</para>
385  *   <para>#ClutterActor will also parse every positional and dimensional
386  *   property defined as a string through clutter_units_from_string(); you
387  *   should read the documentation for the #ClutterUnits parser format for
388  *   the valid units and syntax.</para>
389  * </refsect2>
390  *
391  * <refsect2 id="ClutterActor-custom-animatable-properties">
392  *   <title>Custom animatable properties</title>
393  *   <para>#ClutterActor allows accessing properties of #ClutterAction,
394  *   #ClutterEffect, and #ClutterConstraint instances associated to an actor
395  *   instance for animation purposes.</para>
396  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
397  *   property it is necessary to set the #ClutterActorMeta:name property on the
398  *   given action or constraint.</para>
399  *   <para>The property can be accessed using the following syntax:</para>
400  *   <informalexample>
401  *     <programlisting>
402  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
403  *     </programlisting>
404  *   </informalexample>
405  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
406  *   <para>The <emphasis>section</emphasis> fragment can be one between
407  *   "actions", "constraints" and "effects".</para>
408  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
409  *   action or constraint, as specified by the #ClutterActorMeta:name
410  *   property.</para>
411  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
412  *   action or constraint property to be animated.</para>
413  *   <para>The example below animates a #ClutterBindConstraint applied to an
414  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
415  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
416  *   its initial state is overlapping the actor to which is bound to.</para>
417  *   <informalexample><programlisting>
418  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
419  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
420  * clutter_actor_add_constraint (rect, constraint);
421  *
422  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
423  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
424  * clutter_actor_add_constraint (rect, constraint);
425  *
426  * clutter_actor_set_reactive (origin, TRUE);
427  *
428  * g_signal_connect (origin, "button-press-event",
429  *                   G_CALLBACK (on_button_press),
430  *                   rect);
431  *   </programlisting></informalexample>
432  *   <para>On button press, the rectangle "slides" from behind the actor to
433  *   which is bound to, using the #ClutterBindConstraint:offset property to
434  *   achieve the effect:</para>
435  *   <informalexample><programlisting>
436  * gboolean
437  * on_button_press (ClutterActor *origin,
438  *                  ClutterEvent *event,
439  *                  ClutterActor *rect)
440  * {
441  *   ClutterTransition *transition;
442  *   ClutterInterval *interval;
443  *
444  *   /&ast; the offset that we want to apply; this will make the actor
445  *    &ast; slide in from behind the origin and rest at the right of
446  *    &ast; the origin, plus a padding value.
447  *    &ast;/
448  *   float new_offset = clutter_actor_get_width (origin) + h_padding;
449  *
450  *   /&ast; the property we wish to animate; the "@constraints" section
451  *    &ast; tells Clutter to check inside the constraints associated
452  *    &ast; with the actor; the "bind-x" section is the name of the
453  *    &ast; constraint; and the "offset" is the name of the property
454  *    &ast; on the constraint.
455  *    &ast;/
456  *   const char *prop = "@constraints.bind-x.offset";
457  *
458  *   /&ast; create a new transition for the given property &ast;/
459  *   transition = clutter_property_transition_new (prop);
460  *
461  *   /&ast; set the easing mode and duration &ast;/
462  *   clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
463  *                                       CLUTTER_EASE_OUT_CUBIC);
464  *   clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
465  *
466  *   /&ast; create the interval with the initial and final values &ast;/
467  *   interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
468  *   clutter_transition_set_interval (transition, interval);
469  *
470  *   /&ast; add the transition to the actor; this causes the animation
471  *    &ast; to start. the name "offsetAnimation" can be used to retrieve
472  *    &ast; the transition later.
473  *    &ast;/
474  *   clutter_actor_add_transition (rect, "offsetAnimation", transition);
475  *
476  *   /&ast; we handled the event &ast;/
477  *   return CLUTTER_EVENT_STOP;
478  * }
479  *   </programlisting></informalexample>
480  * </refsect2>
481  */
482
483 /**
484  * CLUTTER_ACTOR_IS_MAPPED:
485  * @a: a #ClutterActor
486  *
487  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
488  *
489  * The mapped state is set when the actor is visible and all its parents up
490  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
491  *
492  * This check can be used to see if an actor is going to be painted, as only
493  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
494  *
495  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
496  * not be checked directly; instead, the recommended usage is to connect a
497  * handler on the #GObject::notify signal for the #ClutterActor:mapped
498  * property of #ClutterActor, and check the presence of
499  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
500  *
501  * It is also important to note that Clutter may delay the changes of
502  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
503  * limitations, or during the reparenting of an actor, to optimize
504  * unnecessary (and potentially expensive) state changes.
505  *
506  * Since: 0.2
507  */
508
509 /**
510  * CLUTTER_ACTOR_IS_REALIZED:
511  * @a: a #ClutterActor
512  *
513  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
514  *
515  * The realized state has an actor-dependant interpretation. If an
516  * actor wants to delay allocating resources until it is attached to a
517  * stage, it may use the realize state to do so. However it is
518  * perfectly acceptable for an actor to allocate Cogl resources before
519  * being realized because there is only one drawing context used by Clutter
520  * so any resources will work on any stage.  If an actor is mapped it
521  * must also be realized, but an actor can be realized and unmapped
522  * (this is so hiding an actor temporarily doesn't do an expensive
523  * unrealize/realize).
524  *
525  * To be realized an actor must be inside a stage, and all its parents
526  * must be realized.
527  *
528  * Since: 0.2
529  */
530
531 /**
532  * CLUTTER_ACTOR_IS_VISIBLE:
533  * @a: a #ClutterActor
534  *
535  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
536  * Equivalent to the ClutterActor::visible object property.
537  *
538  * Note that an actor is only painted onscreen if it's mapped, which
539  * means it's visible, and all its parents are visible, and one of the
540  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
541  *
542  * Since: 0.2
543  */
544
545 /**
546  * CLUTTER_ACTOR_IS_REACTIVE:
547  * @a: a #ClutterActor
548  *
549  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
550  *
551  * Only reactive actors will receive event-related signals.
552  *
553  * Since: 0.6
554  */
555
556 #ifdef HAVE_CONFIG_H
557 #include "config.h"
558 #endif
559
560 #include <math.h>
561
562 #include <gobject/gvaluecollector.h>
563
564 #include <cogl/cogl.h>
565
566 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
567 #define CLUTTER_ENABLE_EXPERIMENTAL_API
568
569 #include "clutter-actor-private.h"
570
571 #include "clutter-action.h"
572 #include "clutter-actor-meta-private.h"
573 #include "clutter-animatable.h"
574 #include "clutter-color-static.h"
575 #include "clutter-color.h"
576 #include "clutter-constraint.h"
577 #include "clutter-container.h"
578 #include "clutter-content-private.h"
579 #include "clutter-debug.h"
580 #include "clutter-effect-private.h"
581 #include "clutter-enum-types.h"
582 #include "clutter-fixed-layout.h"
583 #include "clutter-flatten-effect.h"
584 #include "clutter-interval.h"
585 #include "clutter-main.h"
586 #include "clutter-marshal.h"
587 #include "clutter-paint-nodes.h"
588 #include "clutter-paint-node-private.h"
589 #include "clutter-paint-volume-private.h"
590 #include "clutter-private.h"
591 #include "clutter-profile.h"
592 #include "clutter-property-transition.h"
593 #include "clutter-scriptable.h"
594 #include "clutter-script-private.h"
595 #include "clutter-stage-private.h"
596 #include "clutter-timeline.h"
597 #include "clutter-transition.h"
598 #include "clutter-units.h"
599
600 #include "deprecated/clutter-actor.h"
601 #include "deprecated/clutter-behaviour.h"
602 #include "deprecated/clutter-container.h"
603
604 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
605 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
606
607 /* Internal enum used to control mapped state update.  This is a hint
608  * which indicates when to do something other than just enforce
609  * invariants.
610  */
611 typedef enum {
612   MAP_STATE_CHECK,           /* just enforce invariants. */
613   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
614                               * used when about to unparent.
615                               */
616   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
617                               * used to set mapped on toplevels.
618                               */
619   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
620                               * used just before unmapping parent.
621                               */
622 } MapStateChange;
623
624 /* 3 entries should be a good compromise, few layout managers
625  * will ask for 3 different preferred size in each allocation cycle */
626 #define N_CACHED_SIZE_REQUESTS 3
627
628 struct _ClutterActorPrivate
629 {
630   /* request mode */
631   ClutterRequestMode request_mode;
632
633   /* our cached size requests for different width / height */
634   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
635   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
636
637   /* An age of 0 means the entry is not set */
638   guint cached_height_age;
639   guint cached_width_age;
640
641   /* the bounding box of the actor, relative to the parent's
642    * allocation
643    */
644   ClutterActorBox allocation;
645   ClutterAllocationFlags allocation_flags;
646
647   /* clip, in actor coordinates */
648   cairo_rectangle_t clip;
649
650   /* the cached transformation matrix; see apply_transform() */
651   CoglMatrix transform;
652
653   guint8 opacity;
654   gint opacity_override;
655
656   ClutterOffscreenRedirect offscreen_redirect;
657
658   /* This is an internal effect used to implement the
659      offscreen-redirect property */
660   ClutterEffect *flatten_effect;
661
662   /* scene graph */
663   ClutterActor *parent;
664   ClutterActor *prev_sibling;
665   ClutterActor *next_sibling;
666   ClutterActor *first_child;
667   ClutterActor *last_child;
668
669   gint n_children;
670
671   /* tracks whenever the children of an actor are changed; the
672    * age is incremented by 1 whenever an actor is added or
673    * removed. the age is not incremented when the first or the
674    * last child pointers are changed, or when grandchildren of
675    * an actor are changed.
676    */
677   gint age;
678
679   gchar *name; /* a non-unique name, used for debugging */
680   guint32 id; /* unique id, used for backward compatibility */
681
682   gint32 pick_id; /* per-stage unique id, used for picking */
683
684   /* a back-pointer to the Pango context that we can use
685    * to create pre-configured PangoLayout
686    */
687   PangoContext *pango_context;
688
689   /* the text direction configured for this child - either by
690    * application code, or by the actor's parent
691    */
692   ClutterTextDirection text_direction;
693
694   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
695   gint internal_child;
696
697   /* meta classes */
698   ClutterMetaGroup *actions;
699   ClutterMetaGroup *constraints;
700   ClutterMetaGroup *effects;
701
702   /* delegate object used to allocate the children of this actor */
703   ClutterLayoutManager *layout_manager;
704
705   /* delegate object used to paint the contents of this actor */
706   ClutterContent *content;
707
708   ClutterActorBox content_box;
709   ClutterContentGravity content_gravity;
710   ClutterScalingFilter min_filter;
711   ClutterScalingFilter mag_filter;
712
713   /* used when painting, to update the paint volume */
714   ClutterEffect *current_effect;
715
716   /* This is used to store an effect which needs to be redrawn. A
717      redraw can be queued to start from a particular effect. This is
718      used by parametrised effects that can cache an image of the
719      actor. If a parameter of the effect changes then it only needs to
720      redraw the cached image, not the actual actor. The pointer is
721      only valid if is_dirty == TRUE. If the pointer is NULL then the
722      whole actor is dirty. */
723   ClutterEffect *effect_to_redraw;
724
725   /* This is used when painting effects to implement the
726      clutter_actor_continue_paint() function. It points to the node in
727      the list of effects that is next in the chain */
728   const GList *next_effect_to_paint;
729
730   ClutterPaintVolume paint_volume;
731
732   /* NB: This volume isn't relative to this actor, it is in eye
733    * coordinates so that it can remain valid after the actor changes.
734    */
735   ClutterPaintVolume last_paint_volume;
736
737   ClutterStageQueueRedrawEntry *queue_redraw_entry;
738
739   ClutterColor bg_color;
740
741   /* bitfields */
742
743   /* fixed position and sizes */
744   guint position_set                : 1;
745   guint min_width_set               : 1;
746   guint min_height_set              : 1;
747   guint natural_width_set           : 1;
748   guint natural_height_set          : 1;
749   /* cached request is invalid (implies allocation is too) */
750   guint needs_width_request         : 1;
751   /* cached request is invalid (implies allocation is too) */
752   guint needs_height_request        : 1;
753   /* cached allocation is invalid (request has changed, probably) */
754   guint needs_allocation            : 1;
755   guint show_on_set_parent          : 1;
756   guint has_clip                    : 1;
757   guint clip_to_allocation          : 1;
758   guint enable_model_view_transform : 1;
759   guint enable_paint_unmapped       : 1;
760   guint has_pointer                 : 1;
761   guint propagated_one_redraw       : 1;
762   guint paint_volume_valid          : 1;
763   guint last_paint_volume_valid     : 1;
764   guint in_clone_paint              : 1;
765   guint transform_valid             : 1;
766   /* This is TRUE if anything has queued a redraw since we were last
767      painted. In this case effect_to_redraw will point to an effect
768      the redraw was queued from or it will be NULL if the redraw was
769      queued without an effect. */
770   guint is_dirty                    : 1;
771   guint bg_color_set                : 1;
772   guint content_box_valid           : 1;
773 };
774
775 enum
776 {
777   PROP_0,
778
779   PROP_NAME,
780
781   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
782    * when set they force a size request, when gotten they
783    * get the allocation if the allocation is valid, and the
784    * request otherwise
785    */
786   PROP_X,
787   PROP_Y,
788   PROP_WIDTH,
789   PROP_HEIGHT,
790
791   /* Then the rest of these size-related properties are the "actual"
792    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
793    */
794   PROP_FIXED_X,
795   PROP_FIXED_Y,
796
797   PROP_FIXED_POSITION_SET,
798
799   PROP_MIN_WIDTH,
800   PROP_MIN_WIDTH_SET,
801
802   PROP_MIN_HEIGHT,
803   PROP_MIN_HEIGHT_SET,
804
805   PROP_NATURAL_WIDTH,
806   PROP_NATURAL_WIDTH_SET,
807
808   PROP_NATURAL_HEIGHT,
809   PROP_NATURAL_HEIGHT_SET,
810
811   PROP_REQUEST_MODE,
812
813   /* Allocation properties are read-only */
814   PROP_ALLOCATION,
815
816   PROP_DEPTH,
817
818   PROP_CLIP,
819   PROP_HAS_CLIP,
820   PROP_CLIP_TO_ALLOCATION,
821
822   PROP_OPACITY,
823
824   PROP_OFFSCREEN_REDIRECT,
825
826   PROP_VISIBLE,
827   PROP_MAPPED,
828   PROP_REALIZED,
829   PROP_REACTIVE,
830
831   PROP_SCALE_X,
832   PROP_SCALE_Y,
833   PROP_SCALE_CENTER_X,
834   PROP_SCALE_CENTER_Y,
835   PROP_SCALE_GRAVITY,
836
837   PROP_ROTATION_ANGLE_X,
838   PROP_ROTATION_ANGLE_Y,
839   PROP_ROTATION_ANGLE_Z,
840   PROP_ROTATION_CENTER_X,
841   PROP_ROTATION_CENTER_Y,
842   PROP_ROTATION_CENTER_Z,
843   /* This property only makes sense for the z rotation because the
844      others would depend on the actor having a size along the
845      z-axis */
846   PROP_ROTATION_CENTER_Z_GRAVITY,
847
848   PROP_ANCHOR_X,
849   PROP_ANCHOR_Y,
850   PROP_ANCHOR_GRAVITY,
851
852   PROP_SHOW_ON_SET_PARENT,
853
854   PROP_TEXT_DIRECTION,
855   PROP_HAS_POINTER,
856
857   PROP_ACTIONS,
858   PROP_CONSTRAINTS,
859   PROP_EFFECT,
860
861   PROP_LAYOUT_MANAGER,
862
863   PROP_X_ALIGN,
864   PROP_Y_ALIGN,
865   PROP_MARGIN_TOP,
866   PROP_MARGIN_BOTTOM,
867   PROP_MARGIN_LEFT,
868   PROP_MARGIN_RIGHT,
869
870   PROP_BACKGROUND_COLOR,
871   PROP_BACKGROUND_COLOR_SET,
872
873   PROP_FIRST_CHILD,
874   PROP_LAST_CHILD,
875
876   PROP_CONTENT,
877   PROP_CONTENT_GRAVITY,
878   PROP_CONTENT_BOX,
879   PROP_MINIFICATION_FILTER,
880   PROP_MAGNIFICATION_FILTER,
881
882   PROP_LAST
883 };
884
885 static GParamSpec *obj_props[PROP_LAST];
886
887 enum
888 {
889   SHOW,
890   HIDE,
891   DESTROY,
892   PARENT_SET,
893   KEY_FOCUS_IN,
894   KEY_FOCUS_OUT,
895   PAINT,
896   PICK,
897   REALIZE,
898   UNREALIZE,
899   QUEUE_REDRAW,
900   QUEUE_RELAYOUT,
901   EVENT,
902   CAPTURED_EVENT,
903   BUTTON_PRESS_EVENT,
904   BUTTON_RELEASE_EVENT,
905   SCROLL_EVENT,
906   KEY_PRESS_EVENT,
907   KEY_RELEASE_EVENT,
908   MOTION_EVENT,
909   ENTER_EVENT,
910   LEAVE_EVENT,
911   ALLOCATION_CHANGED,
912   TRANSITIONS_COMPLETED,
913
914   LAST_SIGNAL
915 };
916
917 static guint actor_signals[LAST_SIGNAL] = { 0, };
918
919 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
920 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
921 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
922 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
923
924 /* These setters are all static for now, maybe they should be in the
925  * public API, but they are perhaps obscure enough to leave only as
926  * properties
927  */
928 static void clutter_actor_set_min_width          (ClutterActor *self,
929                                                   gfloat        min_width);
930 static void clutter_actor_set_min_height         (ClutterActor *self,
931                                                   gfloat        min_height);
932 static void clutter_actor_set_natural_width      (ClutterActor *self,
933                                                   gfloat        natural_width);
934 static void clutter_actor_set_natural_height     (ClutterActor *self,
935                                                   gfloat        natural_height);
936 static void clutter_actor_set_min_width_set      (ClutterActor *self,
937                                                   gboolean      use_min_width);
938 static void clutter_actor_set_min_height_set     (ClutterActor *self,
939                                                   gboolean      use_min_height);
940 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
941                                                   gboolean  use_natural_width);
942 static void clutter_actor_set_natural_height_set (ClutterActor *self,
943                                                   gboolean  use_natural_height);
944 static void clutter_actor_update_map_state       (ClutterActor  *self,
945                                                   MapStateChange change);
946 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
947
948 /* Helper routines for managing anchor coords */
949 static void clutter_anchor_coord_get_units (ClutterActor      *self,
950                                             const AnchorCoord *coord,
951                                             gfloat            *x,
952                                             gfloat            *y,
953                                             gfloat            *z);
954 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
955                                             gfloat             x,
956                                             gfloat             y,
957                                             gfloat             z);
958
959 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
960 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
961                                                         ClutterGravity     gravity);
962
963 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
964
965 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
966
967 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
968                                                                ClutterActor *ancestor,
969                                                                CoglMatrix *matrix);
970
971 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
972
973 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
974
975 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
976                                                                 const ClutterColor *color);
977
978 static void on_layout_manager_changed (ClutterLayoutManager *manager,
979                                        ClutterActor         *self);
980
981 /* Helper macro which translates by the anchor coord, applies the
982    given transformation and then translates back */
983 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
984   gfloat _tx, _ty, _tz;                                                \
985   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
986   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
987   { _transform; }                                                      \
988   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
989
990 static GQuark quark_shader_data = 0;
991 static GQuark quark_actor_layout_info = 0;
992 static GQuark quark_actor_transform_info = 0;
993 static GQuark quark_actor_animation_info = 0;
994
995 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
996                          clutter_actor,
997                          G_TYPE_INITIALLY_UNOWNED,
998                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
999                                                 clutter_container_iface_init)
1000                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1001                                                 clutter_scriptable_iface_init)
1002                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1003                                                 clutter_animatable_iface_init)
1004                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1005                                                 atk_implementor_iface_init));
1006
1007 /*< private >
1008  * clutter_actor_get_debug_name:
1009  * @actor: a #ClutterActor
1010  *
1011  * Retrieves a printable name of @actor for debugging messages
1012  *
1013  * Return value: a string with a printable name
1014  */
1015 const gchar *
1016 _clutter_actor_get_debug_name (ClutterActor *actor)
1017 {
1018   return actor->priv->name != NULL ? actor->priv->name
1019                                    : G_OBJECT_TYPE_NAME (actor);
1020 }
1021
1022 #ifdef CLUTTER_ENABLE_DEBUG
1023 /* XXX - this is for debugging only, remove once working (or leave
1024  * in only in some debug mode). Should leave it for a little while
1025  * until we're confident in the new map/realize/visible handling.
1026  */
1027 static inline void
1028 clutter_actor_verify_map_state (ClutterActor *self)
1029 {
1030   ClutterActorPrivate *priv = self->priv;
1031
1032   if (CLUTTER_ACTOR_IS_REALIZED (self))
1033     {
1034       /* all bets are off during reparent when we're potentially realized,
1035        * but should not be according to invariants
1036        */
1037       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1038         {
1039           if (priv->parent == NULL)
1040             {
1041               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1042                 {
1043                 }
1044               else
1045                 g_warning ("Realized non-toplevel actor '%s' should "
1046                            "have a parent",
1047                            _clutter_actor_get_debug_name (self));
1048             }
1049           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1050             {
1051               g_warning ("Realized actor %s has an unrealized parent %s",
1052                          _clutter_actor_get_debug_name (self),
1053                          _clutter_actor_get_debug_name (priv->parent));
1054             }
1055         }
1056     }
1057
1058   if (CLUTTER_ACTOR_IS_MAPPED (self))
1059     {
1060       if (!CLUTTER_ACTOR_IS_REALIZED (self))
1061         g_warning ("Actor '%s' is mapped but not realized",
1062                    _clutter_actor_get_debug_name (self));
1063
1064       /* remaining bets are off during reparent when we're potentially
1065        * mapped, but should not be according to invariants
1066        */
1067       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1068         {
1069           if (priv->parent == NULL)
1070             {
1071               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1072                 {
1073                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1074                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1075                     {
1076                       g_warning ("Toplevel actor '%s' is mapped "
1077                                  "but not visible",
1078                                  _clutter_actor_get_debug_name (self));
1079                     }
1080                 }
1081               else
1082                 {
1083                   g_warning ("Mapped actor '%s' should have a parent",
1084                              _clutter_actor_get_debug_name (self));
1085                 }
1086             }
1087           else
1088             {
1089               ClutterActor *iter = self;
1090
1091               /* check for the enable_paint_unmapped flag on the actor
1092                * and parents; if the flag is enabled at any point of this
1093                * branch of the scene graph then all the later checks
1094                * become pointless
1095                */
1096               while (iter != NULL)
1097                 {
1098                   if (iter->priv->enable_paint_unmapped)
1099                     return;
1100
1101                   iter = iter->priv->parent;
1102                 }
1103
1104               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1105                 {
1106                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1107                              "is not visible",
1108                              _clutter_actor_get_debug_name (self),
1109                              _clutter_actor_get_debug_name (priv->parent));
1110                 }
1111
1112               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1113                 {
1114                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1115                              "is not realized",
1116                              _clutter_actor_get_debug_name (self),
1117                              _clutter_actor_get_debug_name (priv->parent));
1118                 }
1119
1120               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1121                 {
1122                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1123                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1124                                "parent '%s' is not mapped",
1125                                _clutter_actor_get_debug_name (self),
1126                                _clutter_actor_get_debug_name (priv->parent));
1127                 }
1128             }
1129         }
1130     }
1131 }
1132
1133 #endif /* CLUTTER_ENABLE_DEBUG */
1134
1135 static void
1136 clutter_actor_set_mapped (ClutterActor *self,
1137                           gboolean      mapped)
1138 {
1139   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1140     return;
1141
1142   if (mapped)
1143     {
1144       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1145       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1146     }
1147   else
1148     {
1149       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1150       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1151     }
1152 }
1153
1154 /* this function updates the mapped and realized states according to
1155  * invariants, in the appropriate order.
1156  */
1157 static void
1158 clutter_actor_update_map_state (ClutterActor  *self,
1159                                 MapStateChange change)
1160 {
1161   gboolean was_mapped;
1162
1163   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1164
1165   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1166     {
1167       /* the mapped flag on top-level actors must be set by the
1168        * per-backend implementation because it might be asynchronous.
1169        *
1170        * That is, the MAPPED flag on toplevels currently tracks the X
1171        * server mapped-ness of the window, while the expected behavior
1172        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1173        * This creates some weird complexity by breaking the invariant
1174        * that if we're visible and all ancestors shown then we are
1175        * also mapped - instead, we are mapped if all ancestors
1176        * _possibly excepting_ the stage are mapped. The stage
1177        * will map/unmap for example when it is minimized or
1178        * moved to another workspace.
1179        *
1180        * So, the only invariant on the stage is that if visible it
1181        * should be realized, and that it has to be visible to be
1182        * mapped.
1183        */
1184       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1185         clutter_actor_realize (self);
1186
1187       switch (change)
1188         {
1189         case MAP_STATE_CHECK:
1190           break;
1191
1192         case MAP_STATE_MAKE_MAPPED:
1193           g_assert (!was_mapped);
1194           clutter_actor_set_mapped (self, TRUE);
1195           break;
1196
1197         case MAP_STATE_MAKE_UNMAPPED:
1198           g_assert (was_mapped);
1199           clutter_actor_set_mapped (self, FALSE);
1200           break;
1201
1202         case MAP_STATE_MAKE_UNREALIZED:
1203           /* we only use MAKE_UNREALIZED in unparent,
1204            * and unparenting a stage isn't possible.
1205            * If someone wants to just unrealize a stage
1206            * then clutter_actor_unrealize() doesn't
1207            * go through this codepath.
1208            */
1209           g_warning ("Trying to force unrealize stage is not allowed");
1210           break;
1211         }
1212
1213       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1214           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1215           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1216         {
1217           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1218                      "it is somehow still mapped",
1219                      _clutter_actor_get_debug_name (self));
1220         }
1221     }
1222   else
1223     {
1224       ClutterActorPrivate *priv = self->priv;
1225       ClutterActor *parent = priv->parent;
1226       gboolean should_be_mapped;
1227       gboolean may_be_realized;
1228       gboolean must_be_realized;
1229
1230       should_be_mapped = FALSE;
1231       may_be_realized = TRUE;
1232       must_be_realized = FALSE;
1233
1234       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1235         {
1236           may_be_realized = FALSE;
1237         }
1238       else
1239         {
1240           /* Maintain invariant that if parent is mapped, and we are
1241            * visible, then we are mapped ...  unless parent is a
1242            * stage, in which case we map regardless of parent's map
1243            * state but do require stage to be visible and realized.
1244            *
1245            * If parent is realized, that does not force us to be
1246            * realized; but if parent is unrealized, that does force
1247            * us to be unrealized.
1248            *
1249            * The reason we don't force children to realize with
1250            * parents is _clutter_actor_rerealize(); if we require that
1251            * a realized parent means children are realized, then to
1252            * unrealize an actor we would have to unrealize its
1253            * parents, which would end up meaning unrealizing and
1254            * hiding the entire stage. So we allow unrealizing a
1255            * child (as long as that child is not mapped) while that
1256            * child still has a realized parent.
1257            *
1258            * Also, if we unrealize from leaf nodes to root, and
1259            * realize from root to leaf, the invariants are never
1260            * violated if we allow children to be unrealized
1261            * while parents are realized.
1262            *
1263            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1264            * to force us to unmap, even though parent is still
1265            * mapped. This is because we're unmapping from leaf nodes
1266            * up to root nodes.
1267            */
1268           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1269               change != MAP_STATE_MAKE_UNMAPPED)
1270             {
1271               gboolean parent_is_visible_realized_toplevel;
1272
1273               parent_is_visible_realized_toplevel =
1274                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1275                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1276                  CLUTTER_ACTOR_IS_REALIZED (parent));
1277
1278               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1279                   parent_is_visible_realized_toplevel)
1280                 {
1281                   must_be_realized = TRUE;
1282                   should_be_mapped = TRUE;
1283                 }
1284             }
1285
1286           /* if the actor has been set to be painted even if unmapped
1287            * then we should map it and check for realization as well;
1288            * this is an override for the branch of the scene graph
1289            * which begins with this node
1290            */
1291           if (priv->enable_paint_unmapped)
1292             {
1293               if (priv->parent == NULL)
1294                 g_warning ("Attempting to map an unparented actor '%s'",
1295                            _clutter_actor_get_debug_name (self));
1296
1297               should_be_mapped = TRUE;
1298               must_be_realized = TRUE;
1299             }
1300
1301           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1302             may_be_realized = FALSE;
1303         }
1304
1305       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1306         {
1307           if (parent == NULL)
1308             g_warning ("Attempting to map a child that does not "
1309                        "meet the necessary invariants: the actor '%s' "
1310                        "has no parent",
1311                        _clutter_actor_get_debug_name (self));
1312           else
1313             g_warning ("Attempting to map a child that does not "
1314                        "meet the necessary invariants: the actor '%s' "
1315                        "is parented to an unmapped actor '%s'",
1316                        _clutter_actor_get_debug_name (self),
1317                        _clutter_actor_get_debug_name (priv->parent));
1318         }
1319
1320       /* If in reparent, we temporarily suspend unmap and unrealize.
1321        *
1322        * We want to go in the order "realize, map" and "unmap, unrealize"
1323        */
1324
1325       /* Unmap */
1326       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1327         clutter_actor_set_mapped (self, FALSE);
1328
1329       /* Realize */
1330       if (must_be_realized)
1331         clutter_actor_realize (self);
1332
1333       /* if we must be realized then we may be, presumably */
1334       g_assert (!(must_be_realized && !may_be_realized));
1335
1336       /* Unrealize */
1337       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1338         clutter_actor_unrealize_not_hiding (self);
1339
1340       /* Map */
1341       if (should_be_mapped)
1342         {
1343           if (!must_be_realized)
1344             g_warning ("Somehow we think actor '%s' should be mapped but "
1345                        "not realized, which isn't allowed",
1346                        _clutter_actor_get_debug_name (self));
1347
1348           /* realization is allowed to fail (though I don't know what
1349            * an app is supposed to do about that - shouldn't it just
1350            * be a g_error? anyway, we have to avoid mapping if this
1351            * happens)
1352            */
1353           if (CLUTTER_ACTOR_IS_REALIZED (self))
1354             clutter_actor_set_mapped (self, TRUE);
1355         }
1356     }
1357
1358 #ifdef CLUTTER_ENABLE_DEBUG
1359   /* check all invariants were kept */
1360   clutter_actor_verify_map_state (self);
1361 #endif
1362 }
1363
1364 static void
1365 clutter_actor_real_map (ClutterActor *self)
1366 {
1367   ClutterActorPrivate *priv = self->priv;
1368   ClutterActor *stage, *iter;
1369
1370   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1371
1372   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1373                 _clutter_actor_get_debug_name (self));
1374
1375   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1376
1377   stage = _clutter_actor_get_stage_internal (self);
1378   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1379
1380   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1381                 priv->pick_id,
1382                 _clutter_actor_get_debug_name (self));
1383
1384   /* notify on parent mapped before potentially mapping
1385    * children, so apps see a top-down notification.
1386    */
1387   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1388
1389   for (iter = self->priv->first_child;
1390        iter != NULL;
1391        iter = iter->priv->next_sibling)
1392     {
1393       clutter_actor_map (iter);
1394     }
1395 }
1396
1397 /**
1398  * clutter_actor_map:
1399  * @self: A #ClutterActor
1400  *
1401  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1402  * and realizes its children if they are visible. Does nothing if the
1403  * actor is not visible.
1404  *
1405  * Calling this function is strongly disencouraged: the default
1406  * implementation of #ClutterActorClass.map() will map all the children
1407  * of an actor when mapping its parent.
1408  *
1409  * When overriding map, it is mandatory to chain up to the parent
1410  * implementation.
1411  *
1412  * Since: 1.0
1413  */
1414 void
1415 clutter_actor_map (ClutterActor *self)
1416 {
1417   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1418
1419   if (CLUTTER_ACTOR_IS_MAPPED (self))
1420     return;
1421
1422   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1423     return;
1424
1425   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1426 }
1427
1428 static void
1429 clutter_actor_real_unmap (ClutterActor *self)
1430 {
1431   ClutterActorPrivate *priv = self->priv;
1432   ClutterActor *iter;
1433
1434   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1435
1436   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1437                 _clutter_actor_get_debug_name (self));
1438
1439   for (iter = self->priv->first_child;
1440        iter != NULL;
1441        iter = iter->priv->next_sibling)
1442     {
1443       clutter_actor_unmap (iter);
1444     }
1445
1446   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1447
1448   /* clear the contents of the last paint volume, so that hiding + moving +
1449    * showing will not result in the wrong area being repainted
1450    */
1451   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1452   priv->last_paint_volume_valid = TRUE;
1453
1454   /* notify on parent mapped after potentially unmapping
1455    * children, so apps see a bottom-up notification.
1456    */
1457   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1458
1459   /* relinquish keyboard focus if we were unmapped while owning it */
1460   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1461     {
1462       ClutterStage *stage;
1463
1464       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1465
1466       if (stage != NULL)
1467         _clutter_stage_release_pick_id (stage, priv->pick_id);
1468
1469       priv->pick_id = -1;
1470
1471       if (stage != NULL &&
1472           clutter_stage_get_key_focus (stage) == self)
1473         {
1474           clutter_stage_set_key_focus (stage, NULL);
1475         }
1476     }
1477 }
1478
1479 /**
1480  * clutter_actor_unmap:
1481  * @self: A #ClutterActor
1482  *
1483  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1484  * unmaps its children if they were mapped.
1485  *
1486  * Calling this function is not encouraged: the default #ClutterActor
1487  * implementation of #ClutterActorClass.unmap() will also unmap any
1488  * eventual children by default when their parent is unmapped.
1489  *
1490  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1491  * chain up to the parent implementation.
1492  *
1493  * <note>It is important to note that the implementation of the
1494  * #ClutterActorClass.unmap() virtual function may be called after
1495  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1496  * implementation, but it is guaranteed to be called before the
1497  * #GObjectClass.finalize() implementation.</note>
1498  *
1499  * Since: 1.0
1500  */
1501 void
1502 clutter_actor_unmap (ClutterActor *self)
1503 {
1504   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1505
1506   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1507     return;
1508
1509   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1510 }
1511
1512 static void
1513 clutter_actor_real_show (ClutterActor *self)
1514 {
1515   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1516     {
1517       ClutterActorPrivate *priv = self->priv;
1518
1519       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1520
1521       /* we notify on the "visible" flag in the clutter_actor_show()
1522        * wrapper so the entire show signal emission completes first
1523        * (?)
1524        */
1525       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1526
1527       /* we queue a relayout unless the actor is inside a
1528        * container that explicitly told us not to
1529        */
1530       if (priv->parent != NULL &&
1531           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1532         {
1533           /* While an actor is hidden the parent may not have
1534            * allocated/requested so we need to start from scratch
1535            * and avoid the short-circuiting in
1536            * clutter_actor_queue_relayout().
1537            */
1538           priv->needs_width_request  = FALSE;
1539           priv->needs_height_request = FALSE;
1540           priv->needs_allocation     = FALSE;
1541           clutter_actor_queue_relayout (self);
1542         }
1543     }
1544 }
1545
1546 static inline void
1547 set_show_on_set_parent (ClutterActor *self,
1548                         gboolean      set_show)
1549 {
1550   ClutterActorPrivate *priv = self->priv;
1551
1552   set_show = !!set_show;
1553
1554   if (priv->show_on_set_parent == set_show)
1555     return;
1556
1557   if (priv->parent == NULL)
1558     {
1559       priv->show_on_set_parent = set_show;
1560       g_object_notify_by_pspec (G_OBJECT (self),
1561                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1562     }
1563 }
1564
1565 /**
1566  * clutter_actor_show:
1567  * @self: A #ClutterActor
1568  *
1569  * Flags an actor to be displayed. An actor that isn't shown will not
1570  * be rendered on the stage.
1571  *
1572  * Actors are visible by default.
1573  *
1574  * If this function is called on an actor without a parent, the
1575  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1576  * effect.
1577  */
1578 void
1579 clutter_actor_show (ClutterActor *self)
1580 {
1581   ClutterActorPrivate *priv;
1582
1583   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1584
1585   /* simple optimization */
1586   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1587     {
1588       /* we still need to set the :show-on-set-parent property, in
1589        * case show() is called on an unparented actor
1590        */
1591       set_show_on_set_parent (self, TRUE);
1592       return;
1593     }
1594
1595 #ifdef CLUTTER_ENABLE_DEBUG
1596   clutter_actor_verify_map_state (self);
1597 #endif
1598
1599   priv = self->priv;
1600
1601   g_object_freeze_notify (G_OBJECT (self));
1602
1603   set_show_on_set_parent (self, TRUE);
1604
1605   g_signal_emit (self, actor_signals[SHOW], 0);
1606   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1607
1608   if (priv->parent != NULL)
1609     clutter_actor_queue_redraw (priv->parent);
1610
1611   g_object_thaw_notify (G_OBJECT (self));
1612 }
1613
1614 /**
1615  * clutter_actor_show_all:
1616  * @self: a #ClutterActor
1617  *
1618  * Calls clutter_actor_show() on all children of an actor (if any).
1619  *
1620  * Since: 0.2
1621  *
1622  * Deprecated: 1.10: Actors are visible by default
1623  */
1624 void
1625 clutter_actor_show_all (ClutterActor *self)
1626 {
1627   ClutterActorClass *klass;
1628
1629   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1630
1631   klass = CLUTTER_ACTOR_GET_CLASS (self);
1632   if (klass->show_all)
1633     klass->show_all (self);
1634 }
1635
1636 static void
1637 clutter_actor_real_hide (ClutterActor *self)
1638 {
1639   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1640     {
1641       ClutterActorPrivate *priv = self->priv;
1642
1643       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1644
1645       /* we notify on the "visible" flag in the clutter_actor_hide()
1646        * wrapper so the entire hide signal emission completes first
1647        * (?)
1648        */
1649       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1650
1651       /* we queue a relayout unless the actor is inside a
1652        * container that explicitly told us not to
1653        */
1654       if (priv->parent != NULL &&
1655           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1656         clutter_actor_queue_relayout (priv->parent);
1657     }
1658 }
1659
1660 /**
1661  * clutter_actor_hide:
1662  * @self: A #ClutterActor
1663  *
1664  * Flags an actor to be hidden. A hidden actor will not be
1665  * rendered on the stage.
1666  *
1667  * Actors are visible by default.
1668  *
1669  * If this function is called on an actor without a parent, the
1670  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1671  * as a side-effect.
1672  */
1673 void
1674 clutter_actor_hide (ClutterActor *self)
1675 {
1676   ClutterActorPrivate *priv;
1677
1678   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1679
1680   /* simple optimization */
1681   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1682     {
1683       /* we still need to set the :show-on-set-parent property, in
1684        * case hide() is called on an unparented actor
1685        */
1686       set_show_on_set_parent (self, FALSE);
1687       return;
1688     }
1689
1690 #ifdef CLUTTER_ENABLE_DEBUG
1691   clutter_actor_verify_map_state (self);
1692 #endif
1693
1694   priv = self->priv;
1695
1696   g_object_freeze_notify (G_OBJECT (self));
1697
1698   set_show_on_set_parent (self, FALSE);
1699
1700   g_signal_emit (self, actor_signals[HIDE], 0);
1701   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1702
1703   if (priv->parent != NULL)
1704     clutter_actor_queue_redraw (priv->parent);
1705
1706   g_object_thaw_notify (G_OBJECT (self));
1707 }
1708
1709 /**
1710  * clutter_actor_hide_all:
1711  * @self: a #ClutterActor
1712  *
1713  * Calls clutter_actor_hide() on all child actors (if any).
1714  *
1715  * Since: 0.2
1716  *
1717  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1718  *   prevent its children from being painted as well.
1719  */
1720 void
1721 clutter_actor_hide_all (ClutterActor *self)
1722 {
1723   ClutterActorClass *klass;
1724
1725   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1726
1727   klass = CLUTTER_ACTOR_GET_CLASS (self);
1728   if (klass->hide_all)
1729     klass->hide_all (self);
1730 }
1731
1732 /**
1733  * clutter_actor_realize:
1734  * @self: A #ClutterActor
1735  *
1736  * Realization informs the actor that it is attached to a stage. It
1737  * can use this to allocate resources if it wanted to delay allocation
1738  * until it would be rendered. However it is perfectly acceptable for
1739  * an actor to create resources before being realized because Clutter
1740  * only ever has a single rendering context so that actor is free to
1741  * be moved from one stage to another.
1742  *
1743  * This function does nothing if the actor is already realized.
1744  *
1745  * Because a realized actor must have realized parent actors, calling
1746  * clutter_actor_realize() will also realize all parents of the actor.
1747  *
1748  * This function does not realize child actors, except in the special
1749  * case that realizing the stage, when the stage is visible, will
1750  * suddenly map (and thus realize) the children of the stage.
1751  **/
1752 void
1753 clutter_actor_realize (ClutterActor *self)
1754 {
1755   ClutterActorPrivate *priv;
1756
1757   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1758
1759   priv = self->priv;
1760
1761 #ifdef CLUTTER_ENABLE_DEBUG
1762   clutter_actor_verify_map_state (self);
1763 #endif
1764
1765   if (CLUTTER_ACTOR_IS_REALIZED (self))
1766     return;
1767
1768   /* To be realized, our parent actors must be realized first.
1769    * This will only succeed if we're inside a toplevel.
1770    */
1771   if (priv->parent != NULL)
1772     clutter_actor_realize (priv->parent);
1773
1774   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1775     {
1776       /* toplevels can be realized at any time */
1777     }
1778   else
1779     {
1780       /* "Fail" the realization if parent is missing or unrealized;
1781        * this should really be a g_warning() not some kind of runtime
1782        * failure; how can an app possibly recover? Instead it's a bug
1783        * in the app and the app should get an explanatory warning so
1784        * someone can fix it. But for now it's too hard to fix this
1785        * because e.g. ClutterTexture needs reworking.
1786        */
1787       if (priv->parent == NULL ||
1788           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1789         return;
1790     }
1791
1792   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1793
1794   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1795   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1796
1797   g_signal_emit (self, actor_signals[REALIZE], 0);
1798
1799   /* Stage actor is allowed to unset the realized flag again in its
1800    * default signal handler, though that is a pathological situation.
1801    */
1802
1803   /* If realization "failed" we'll have to update child state. */
1804   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1805 }
1806
1807 static void
1808 clutter_actor_real_unrealize (ClutterActor *self)
1809 {
1810   /* we must be unmapped (implying our children are also unmapped) */
1811   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1812 }
1813
1814 /**
1815  * clutter_actor_unrealize:
1816  * @self: A #ClutterActor
1817  *
1818  * Unrealization informs the actor that it may be being destroyed or
1819  * moved to another stage. The actor may want to destroy any
1820  * underlying graphics resources at this point. However it is
1821  * perfectly acceptable for it to retain the resources until the actor
1822  * is destroyed because Clutter only ever uses a single rendering
1823  * context and all of the graphics resources are valid on any stage.
1824  *
1825  * Because mapped actors must be realized, actors may not be
1826  * unrealized if they are mapped. This function hides the actor to be
1827  * sure it isn't mapped, an application-visible side effect that you
1828  * may not be expecting.
1829  *
1830  * This function should not be called by application code.
1831  */
1832 void
1833 clutter_actor_unrealize (ClutterActor *self)
1834 {
1835   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1836   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1837
1838 /* This function should not really be in the public API, because
1839  * there isn't a good reason to call it. ClutterActor will already
1840  * unrealize things for you when it's important to do so.
1841  *
1842  * If you were using clutter_actor_unrealize() in a dispose
1843  * implementation, then don't, just chain up to ClutterActor's
1844  * dispose.
1845  *
1846  * If you were using clutter_actor_unrealize() to implement
1847  * unrealizing children of your container, then don't, ClutterActor
1848  * will already take care of that.
1849  *
1850  * If you were using clutter_actor_unrealize() to re-realize to
1851  * create your resources in a different way, then use
1852  * _clutter_actor_rerealize() (inside Clutter) or just call your
1853  * code that recreates your resources directly (outside Clutter).
1854  */
1855
1856 #ifdef CLUTTER_ENABLE_DEBUG
1857   clutter_actor_verify_map_state (self);
1858 #endif
1859
1860   clutter_actor_hide (self);
1861
1862   clutter_actor_unrealize_not_hiding (self);
1863 }
1864
1865 static ClutterActorTraverseVisitFlags
1866 unrealize_actor_before_children_cb (ClutterActor *self,
1867                                     int depth,
1868                                     void *user_data)
1869 {
1870   /* If an actor is already unrealized we know its children have also
1871    * already been unrealized... */
1872   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1873     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1874
1875   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1876
1877   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1878 }
1879
1880 static ClutterActorTraverseVisitFlags
1881 unrealize_actor_after_children_cb (ClutterActor *self,
1882                                    int depth,
1883                                    void *user_data)
1884 {
1885   /* We want to unset the realized flag only _after_
1886    * child actors are unrealized, to maintain invariants.
1887    */
1888   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1889   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1890   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1891 }
1892
1893 /*
1894  * clutter_actor_unrealize_not_hiding:
1895  * @self: A #ClutterActor
1896  *
1897  * Unrealization informs the actor that it may be being destroyed or
1898  * moved to another stage. The actor may want to destroy any
1899  * underlying graphics resources at this point. However it is
1900  * perfectly acceptable for it to retain the resources until the actor
1901  * is destroyed because Clutter only ever uses a single rendering
1902  * context and all of the graphics resources are valid on any stage.
1903  *
1904  * Because mapped actors must be realized, actors may not be
1905  * unrealized if they are mapped. You must hide the actor or one of
1906  * its parents before attempting to unrealize.
1907  *
1908  * This function is separate from clutter_actor_unrealize() because it
1909  * does not automatically hide the actor.
1910  * Actors need not be hidden to be unrealized, they just need to
1911  * be unmapped. In fact we don't want to mess up the application's
1912  * setting of the "visible" flag, so hiding is very undesirable.
1913  *
1914  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1915  * backward compatibility.
1916  */
1917 static void
1918 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1919 {
1920   _clutter_actor_traverse (self,
1921                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1922                            unrealize_actor_before_children_cb,
1923                            unrealize_actor_after_children_cb,
1924                            NULL);
1925 }
1926
1927 /*
1928  * _clutter_actor_rerealize:
1929  * @self: A #ClutterActor
1930  * @callback: Function to call while unrealized
1931  * @data: data for callback
1932  *
1933  * If an actor is already unrealized, this just calls the callback.
1934  *
1935  * If it is realized, it unrealizes temporarily, calls the callback,
1936  * and then re-realizes the actor.
1937  *
1938  * As a side effect, leaves all children of the actor unrealized if
1939  * the actor was realized but not showing.  This is because when we
1940  * unrealize the actor temporarily we must unrealize its children
1941  * (e.g. children of a stage can't be realized if stage window is
1942  * gone). And we aren't clever enough to save the realization state of
1943  * all children. In most cases this should not matter, because
1944  * the children will automatically realize when they next become mapped.
1945  */
1946 void
1947 _clutter_actor_rerealize (ClutterActor    *self,
1948                           ClutterCallback  callback,
1949                           void            *data)
1950 {
1951   gboolean was_mapped;
1952   gboolean was_showing;
1953   gboolean was_realized;
1954
1955   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1956
1957 #ifdef CLUTTER_ENABLE_DEBUG
1958   clutter_actor_verify_map_state (self);
1959 #endif
1960
1961   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1962   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1963   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1964
1965   /* Must be unmapped to unrealize. Note we only have to hide this
1966    * actor if it was mapped (if all parents were showing).  If actor
1967    * is merely visible (but not mapped), then that's fine, we can
1968    * leave it visible.
1969    */
1970   if (was_mapped)
1971     clutter_actor_hide (self);
1972
1973   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1974
1975   /* unrealize self and all children */
1976   clutter_actor_unrealize_not_hiding (self);
1977
1978   if (callback != NULL)
1979     {
1980       (* callback) (self, data);
1981     }
1982
1983   if (was_showing)
1984     clutter_actor_show (self); /* will realize only if mapping implies it */
1985   else if (was_realized)
1986     clutter_actor_realize (self); /* realize self and all parents */
1987 }
1988
1989 static void
1990 clutter_actor_real_pick (ClutterActor       *self,
1991                          const ClutterColor *color)
1992 {
1993   /* the default implementation is just to paint a rectangle
1994    * with the same size of the actor using the passed color
1995    */
1996   if (clutter_actor_should_pick_paint (self))
1997     {
1998       ClutterActorBox box = { 0, };
1999       float width, height;
2000
2001       clutter_actor_get_allocation_box (self, &box);
2002
2003       width = box.x2 - box.x1;
2004       height = box.y2 - box.y1;
2005
2006       cogl_set_source_color4ub (color->red,
2007                                 color->green,
2008                                 color->blue,
2009                                 color->alpha);
2010
2011       cogl_rectangle (0, 0, width, height);
2012     }
2013
2014   /* XXX - this thoroughly sucks, but we need to maintain compatibility
2015    * with existing container classes that override the pick() virtual
2016    * and chain up to the default implementation - otherwise we'll end up
2017    * painting our children twice.
2018    *
2019    * this has to go away for 2.0; hopefully along the pick() itself.
2020    */
2021   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2022     {
2023       ClutterActor *iter;
2024
2025       for (iter = self->priv->first_child;
2026            iter != NULL;
2027            iter = iter->priv->next_sibling)
2028         clutter_actor_paint (iter);
2029     }
2030 }
2031
2032 /**
2033  * clutter_actor_should_pick_paint:
2034  * @self: A #ClutterActor
2035  *
2036  * Should be called inside the implementation of the
2037  * #ClutterActor::pick virtual function in order to check whether
2038  * the actor should paint itself in pick mode or not.
2039  *
2040  * This function should never be called directly by applications.
2041  *
2042  * Return value: %TRUE if the actor should paint its silhouette,
2043  *   %FALSE otherwise
2044  */
2045 gboolean
2046 clutter_actor_should_pick_paint (ClutterActor *self)
2047 {
2048   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2049
2050   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2051       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2052        CLUTTER_ACTOR_IS_REACTIVE (self)))
2053     return TRUE;
2054
2055   return FALSE;
2056 }
2057
2058 static void
2059 clutter_actor_real_get_preferred_width (ClutterActor *self,
2060                                         gfloat        for_height,
2061                                         gfloat       *min_width_p,
2062                                         gfloat       *natural_width_p)
2063 {
2064   ClutterActorPrivate *priv = self->priv;
2065
2066   if (priv->n_children != 0 &&
2067       priv->layout_manager != NULL)
2068     {
2069       ClutterContainer *container = CLUTTER_CONTAINER (self);
2070
2071       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2072                     "for the preferred width",
2073                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2074                     priv->layout_manager);
2075
2076       clutter_layout_manager_get_preferred_width (priv->layout_manager,
2077                                                   container,
2078                                                   for_height,
2079                                                   min_width_p,
2080                                                   natural_width_p);
2081
2082       return;
2083     }
2084
2085   /* Default implementation is always 0x0, usually an actor
2086    * using this default is relying on someone to set the
2087    * request manually
2088    */
2089   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2090
2091   if (min_width_p)
2092     *min_width_p = 0;
2093
2094   if (natural_width_p)
2095     *natural_width_p = 0;
2096 }
2097
2098 static void
2099 clutter_actor_real_get_preferred_height (ClutterActor *self,
2100                                          gfloat        for_width,
2101                                          gfloat       *min_height_p,
2102                                          gfloat       *natural_height_p)
2103 {
2104   ClutterActorPrivate *priv = self->priv;
2105
2106   if (priv->n_children != 0 &&
2107       priv->layout_manager != NULL)
2108     {
2109       ClutterContainer *container = CLUTTER_CONTAINER (self);
2110
2111       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2112                     "for the preferred height",
2113                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2114                     priv->layout_manager);
2115
2116       clutter_layout_manager_get_preferred_height (priv->layout_manager,
2117                                                    container,
2118                                                    for_width,
2119                                                    min_height_p,
2120                                                    natural_height_p);
2121
2122       return;
2123     }
2124   /* Default implementation is always 0x0, usually an actor
2125    * using this default is relying on someone to set the
2126    * request manually
2127    */
2128   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2129
2130   if (min_height_p)
2131     *min_height_p = 0;
2132
2133   if (natural_height_p)
2134     *natural_height_p = 0;
2135 }
2136
2137 static void
2138 clutter_actor_store_old_geometry (ClutterActor    *self,
2139                                   ClutterActorBox *box)
2140 {
2141   *box = self->priv->allocation;
2142 }
2143
2144 static inline void
2145 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2146                                           const ClutterActorBox *old)
2147 {
2148   ClutterActorPrivate *priv = self->priv;
2149   GObject *obj = G_OBJECT (self);
2150
2151   g_object_freeze_notify (obj);
2152
2153   /* to avoid excessive requisition or allocation cycles we
2154    * use the cached values.
2155    *
2156    * - if we don't have an allocation we assume that we need
2157    *   to notify anyway
2158    * - if we don't have a width or a height request we notify
2159    *   width and height
2160    * - if we have a valid allocation then we check the old
2161    *   bounding box with the current allocation and we notify
2162    *   the changes
2163    */
2164   if (priv->needs_allocation)
2165     {
2166       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2167       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2168       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2169       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2170     }
2171   else if (priv->needs_width_request || priv->needs_height_request)
2172     {
2173       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2174       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2175     }
2176   else
2177     {
2178       gfloat x, y;
2179       gfloat width, height;
2180
2181       x = priv->allocation.x1;
2182       y = priv->allocation.y1;
2183       width = priv->allocation.x2 - priv->allocation.x1;
2184       height = priv->allocation.y2 - priv->allocation.y1;
2185
2186       if (x != old->x1)
2187         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2188
2189       if (y != old->y1)
2190         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2191
2192       if (width != (old->x2 - old->x1))
2193         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2194
2195       if (height != (old->y2 - old->y1))
2196         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2197     }
2198
2199   g_object_thaw_notify (obj);
2200 }
2201
2202 /*< private >
2203  * clutter_actor_set_allocation_internal:
2204  * @self: a #ClutterActor
2205  * @box: a #ClutterActorBox
2206  * @flags: allocation flags
2207  *
2208  * Stores the allocation of @self.
2209  *
2210  * This function only performs basic storage and property notification.
2211  *
2212  * This function should be called by clutter_actor_set_allocation()
2213  * and by the default implementation of #ClutterActorClass.allocate().
2214  *
2215  * Return value: %TRUE if the allocation of the #ClutterActor has been
2216  *   changed, and %FALSE otherwise
2217  */
2218 static inline gboolean
2219 clutter_actor_set_allocation_internal (ClutterActor           *self,
2220                                        const ClutterActorBox  *box,
2221                                        ClutterAllocationFlags  flags)
2222 {
2223   ClutterActorPrivate *priv = self->priv;
2224   GObject *obj;
2225   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2226   gboolean flags_changed;
2227   gboolean retval;
2228   ClutterActorBox old_alloc = { 0, };
2229
2230   obj = G_OBJECT (self);
2231
2232   g_object_freeze_notify (obj);
2233
2234   clutter_actor_store_old_geometry (self, &old_alloc);
2235
2236   x1_changed = priv->allocation.x1 != box->x1;
2237   y1_changed = priv->allocation.y1 != box->y1;
2238   x2_changed = priv->allocation.x2 != box->x2;
2239   y2_changed = priv->allocation.y2 != box->y2;
2240
2241   flags_changed = priv->allocation_flags != flags;
2242
2243   priv->allocation = *box;
2244   priv->allocation_flags = flags;
2245
2246   /* allocation is authoritative */
2247   priv->needs_width_request = FALSE;
2248   priv->needs_height_request = FALSE;
2249   priv->needs_allocation = FALSE;
2250
2251   if (x1_changed || y1_changed ||
2252       x2_changed || y2_changed ||
2253       flags_changed)
2254     {
2255       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2256                     _clutter_actor_get_debug_name (self));
2257
2258       priv->transform_valid = FALSE;
2259
2260       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2261
2262       /* if the allocation changes, so does the content box */
2263       if (priv->content != NULL)
2264         {
2265           priv->content_box_valid = FALSE;
2266           g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2267         }
2268
2269       retval = TRUE;
2270     }
2271   else
2272     retval = FALSE;
2273
2274   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2275
2276   g_object_thaw_notify (obj);
2277
2278   return retval;
2279 }
2280
2281 static void clutter_actor_real_allocate (ClutterActor           *self,
2282                                          const ClutterActorBox  *box,
2283                                          ClutterAllocationFlags  flags);
2284
2285 static inline void
2286 clutter_actor_maybe_layout_children (ClutterActor           *self,
2287                                      const ClutterActorBox  *allocation,
2288                                      ClutterAllocationFlags  flags)
2289 {
2290   ClutterActorPrivate *priv = self->priv;
2291
2292   /* this is going to be a bit hard to follow, so let's put an explanation
2293    * here.
2294    *
2295    * we want ClutterActor to have a default layout manager if the actor was
2296    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2297    *
2298    * we also want any subclass of ClutterActor that does not override the
2299    * ::allocate() virtual function to delegate to a layout manager.
2300    *
2301    * finally, we want to allow people subclassing ClutterActor and overriding
2302    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2303    *
2304    * on the other hand, we want existing actor subclasses overriding the
2305    * ::allocate() virtual function and chaining up to the parent's
2306    * implementation to continue working without allocating their children
2307    * twice, or without entering an allocation loop.
2308    *
2309    * for the first two points, we check if the class of the actor is
2310    * overridding the ::allocate() virtual function; if it isn't, then we
2311    * follow through with checking whether we have children and a layout
2312    * manager, and eventually calling clutter_layout_manager_allocate().
2313    *
2314    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2315    * allocation flags that we got passed, and if it is present, we continue
2316    * with the check above.
2317    *
2318    * if neither of these two checks yields a positive result, we just
2319    * assume that the ::allocate() virtual function that resulted in this
2320    * function being called will also allocate the children of the actor.
2321    */
2322
2323   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2324     goto check_layout;
2325
2326   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2327     goto check_layout;
2328
2329   return;
2330
2331 check_layout:
2332   if (priv->n_children != 0 &&
2333       priv->layout_manager != NULL)
2334     {
2335       ClutterContainer *container = CLUTTER_CONTAINER (self);
2336       ClutterAllocationFlags children_flags;
2337       ClutterActorBox children_box;
2338
2339       /* normalize the box passed to the layout manager */
2340       children_box.x1 = children_box.y1 = 0.f;
2341       children_box.x2 = (allocation->x2 - allocation->x1);
2342       children_box.y2 = (allocation->y2 - allocation->y1);
2343
2344       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2345        * the actor's children, since it refers only to the current
2346        * actor's allocation.
2347        */
2348       children_flags = flags;
2349       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2350
2351       CLUTTER_NOTE (LAYOUT,
2352                     "Allocating %d children of %s "
2353                     "at { %.2f, %.2f - %.2f x %.2f } "
2354                     "using %s",
2355                     priv->n_children,
2356                     _clutter_actor_get_debug_name (self),
2357                     allocation->x1,
2358                     allocation->y1,
2359                     (allocation->x2 - allocation->x1),
2360                     (allocation->y2 - allocation->y1),
2361                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2362
2363       clutter_layout_manager_allocate (priv->layout_manager,
2364                                        container,
2365                                        &children_box,
2366                                        children_flags);
2367     }
2368 }
2369
2370 static void
2371 clutter_actor_real_allocate (ClutterActor           *self,
2372                              const ClutterActorBox  *box,
2373                              ClutterAllocationFlags  flags)
2374 {
2375   ClutterActorPrivate *priv = self->priv;
2376   gboolean changed;
2377
2378   g_object_freeze_notify (G_OBJECT (self));
2379
2380   changed = clutter_actor_set_allocation_internal (self, box, flags);
2381
2382   /* we allocate our children before we notify changes in our geometry,
2383    * so that people connecting to properties will be able to get valid
2384    * data out of the sub-tree of the scene graph that has this actor at
2385    * the root.
2386    */
2387   clutter_actor_maybe_layout_children (self, box, flags);
2388
2389   if (changed)
2390     {
2391       ClutterActorBox signal_box = priv->allocation;
2392       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2393
2394       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2395                      &signal_box,
2396                      signal_flags);
2397     }
2398
2399   g_object_thaw_notify (G_OBJECT (self));
2400 }
2401
2402 static void
2403 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2404                                     ClutterActor *origin)
2405 {
2406   /* no point in queuing a redraw on a destroyed actor */
2407   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2408     return;
2409
2410   /* NB: We can't bail out early here if the actor is hidden in case
2411    * the actor bas been cloned. In this case the clone will need to
2412    * receive the signal so it can queue its own redraw.
2413    */
2414
2415   /* calls klass->queue_redraw in default handler */
2416   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2417 }
2418
2419 static void
2420 clutter_actor_real_queue_redraw (ClutterActor *self,
2421                                  ClutterActor *origin)
2422 {
2423   ClutterActor *parent;
2424
2425   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2426                 _clutter_actor_get_debug_name (self),
2427                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2428                                : "same actor");
2429
2430   /* no point in queuing a redraw on a destroyed actor */
2431   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2432     return;
2433
2434   /* If the queue redraw is coming from a child then the actor has
2435      become dirty and any queued effect is no longer valid */
2436   if (self != origin)
2437     {
2438       self->priv->is_dirty = TRUE;
2439       self->priv->effect_to_redraw = NULL;
2440     }
2441
2442   /* If the actor isn't visible, we still had to emit the signal
2443    * to allow for a ClutterClone, but the appearance of the parent
2444    * won't change so we don't have to propagate up the hierarchy.
2445    */
2446   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2447     return;
2448
2449   /* Although we could determine here that a full stage redraw
2450    * has already been queued and immediately bail out, we actually
2451    * guarantee that we will propagate a queue-redraw signal to our
2452    * parent at least once so that it's possible to implement a
2453    * container that tracks which of its children have queued a
2454    * redraw.
2455    */
2456   if (self->priv->propagated_one_redraw)
2457     {
2458       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2459       if (stage != NULL &&
2460           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2461         return;
2462     }
2463
2464   self->priv->propagated_one_redraw = TRUE;
2465
2466   /* notify parents, if they are all visible eventually we'll
2467    * queue redraw on the stage, which queues the redraw idle.
2468    */
2469   parent = clutter_actor_get_parent (self);
2470   if (parent != NULL)
2471     {
2472       /* this will go up recursively */
2473       _clutter_actor_signal_queue_redraw (parent, origin);
2474     }
2475 }
2476
2477 static void
2478 clutter_actor_real_queue_relayout (ClutterActor *self)
2479 {
2480   ClutterActorPrivate *priv = self->priv;
2481
2482   /* no point in queueing a redraw on a destroyed actor */
2483   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2484     return;
2485
2486   priv->needs_width_request  = TRUE;
2487   priv->needs_height_request = TRUE;
2488   priv->needs_allocation     = TRUE;
2489
2490   /* reset the cached size requests */
2491   memset (priv->width_requests, 0,
2492           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2493   memset (priv->height_requests, 0,
2494           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2495
2496   /* We need to go all the way up the hierarchy */
2497   if (priv->parent != NULL)
2498     _clutter_actor_queue_only_relayout (priv->parent);
2499 }
2500
2501 /**
2502  * clutter_actor_apply_relative_transform_to_point:
2503  * @self: A #ClutterActor
2504  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2505  *   default #ClutterStage
2506  * @point: A point as #ClutterVertex
2507  * @vertex: (out caller-allocates): The translated #ClutterVertex
2508  *
2509  * Transforms @point in coordinates relative to the actor into
2510  * ancestor-relative coordinates using the relevant transform
2511  * stack (i.e. scale, rotation, etc).
2512  *
2513  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2514  * this case, the coordinates returned will be the coordinates on
2515  * the stage before the projection is applied. This is different from
2516  * the behaviour of clutter_actor_apply_transform_to_point().
2517  *
2518  * Since: 0.6
2519  */
2520 void
2521 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2522                                                  ClutterActor        *ancestor,
2523                                                  const ClutterVertex *point,
2524                                                  ClutterVertex       *vertex)
2525 {
2526   gfloat w;
2527   CoglMatrix matrix;
2528
2529   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2530   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2531   g_return_if_fail (point != NULL);
2532   g_return_if_fail (vertex != NULL);
2533
2534   *vertex = *point;
2535   w = 1.0;
2536
2537   if (ancestor == NULL)
2538     ancestor = _clutter_actor_get_stage_internal (self);
2539
2540   if (ancestor == NULL)
2541     {
2542       *vertex = *point;
2543       return;
2544     }
2545
2546   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2547   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2548 }
2549
2550 static gboolean
2551 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2552                                          const ClutterVertex *vertices_in,
2553                                          ClutterVertex *vertices_out,
2554                                          int n_vertices)
2555 {
2556   ClutterActor *stage;
2557   CoglMatrix modelview;
2558   CoglMatrix projection;
2559   float viewport[4];
2560
2561   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2562
2563   stage = _clutter_actor_get_stage_internal (self);
2564
2565   /* We really can't do anything meaningful in this case so don't try
2566    * to do any transform */
2567   if (stage == NULL)
2568     return FALSE;
2569
2570   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2571    * that gets us to stage coordinates, we want to go all the way to eye
2572    * coordinates */
2573   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2574
2575   /* Fetch the projection and viewport */
2576   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2577   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2578                                &viewport[0],
2579                                &viewport[1],
2580                                &viewport[2],
2581                                &viewport[3]);
2582
2583   _clutter_util_fully_transform_vertices (&modelview,
2584                                           &projection,
2585                                           viewport,
2586                                           vertices_in,
2587                                           vertices_out,
2588                                           n_vertices);
2589
2590   return TRUE;
2591 }
2592
2593 /**
2594  * clutter_actor_apply_transform_to_point:
2595  * @self: A #ClutterActor
2596  * @point: A point as #ClutterVertex
2597  * @vertex: (out caller-allocates): The translated #ClutterVertex
2598  *
2599  * Transforms @point in coordinates relative to the actor
2600  * into screen-relative coordinates with the current actor
2601  * transformation (i.e. scale, rotation, etc)
2602  *
2603  * Since: 0.4
2604  **/
2605 void
2606 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2607                                         const ClutterVertex *point,
2608                                         ClutterVertex       *vertex)
2609 {
2610   g_return_if_fail (point != NULL);
2611   g_return_if_fail (vertex != NULL);
2612   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2613 }
2614
2615 /*
2616  * _clutter_actor_get_relative_transformation_matrix:
2617  * @self: The actor whose coordinate space you want to transform from.
2618  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2619  *            or %NULL if you want to transform all the way to eye coordinates.
2620  * @matrix: A #CoglMatrix to store the transformation
2621  *
2622  * This gets a transformation @matrix that will transform coordinates from the
2623  * coordinate space of @self into the coordinate space of @ancestor.
2624  *
2625  * For example if you need a matrix that can transform the local actor
2626  * coordinates of @self into stage coordinates you would pass the actor's stage
2627  * pointer as the @ancestor.
2628  *
2629  * If you pass %NULL then the transformation will take you all the way through
2630  * to eye coordinates. This can be useful if you want to extract the entire
2631  * modelview transform that Clutter applies before applying the projection
2632  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2633  * using cogl_set_modelview_matrix() for example then you would want a matrix
2634  * that transforms into eye coordinates.
2635  *
2636  * <note><para>This function explicitly initializes the given @matrix. If you just
2637  * want clutter to multiply a relative transformation with an existing matrix
2638  * you can use clutter_actor_apply_relative_transformation_matrix()
2639  * instead.</para></note>
2640  *
2641  */
2642 /* XXX: We should consider caching the stage relative modelview along with
2643  * the actor itself */
2644 static void
2645 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2646                                                    ClutterActor *ancestor,
2647                                                    CoglMatrix *matrix)
2648 {
2649   cogl_matrix_init_identity (matrix);
2650
2651   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2652 }
2653
2654 /* Project the given @box into stage window coordinates, writing the
2655  * transformed vertices to @verts[]. */
2656 static gboolean
2657 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2658                                           const ClutterActorBox *box,
2659                                           ClutterVertex          verts[])
2660 {
2661   ClutterVertex box_vertices[4];
2662
2663   box_vertices[0].x = box->x1;
2664   box_vertices[0].y = box->y1;
2665   box_vertices[0].z = 0;
2666   box_vertices[1].x = box->x2;
2667   box_vertices[1].y = box->y1;
2668   box_vertices[1].z = 0;
2669   box_vertices[2].x = box->x1;
2670   box_vertices[2].y = box->y2;
2671   box_vertices[2].z = 0;
2672   box_vertices[3].x = box->x2;
2673   box_vertices[3].y = box->y2;
2674   box_vertices[3].z = 0;
2675
2676   return
2677     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2678 }
2679
2680 /**
2681  * clutter_actor_get_allocation_vertices:
2682  * @self: A #ClutterActor
2683  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2684  *   against, or %NULL to use the #ClutterStage
2685  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2686  *   location for an array of 4 #ClutterVertex in which to store the result
2687  *
2688  * Calculates the transformed coordinates of the four corners of the
2689  * actor in the plane of @ancestor. The returned vertices relate to
2690  * the #ClutterActorBox coordinates as follows:
2691  * <itemizedlist>
2692  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2693  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2694  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2695  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2696  * </itemizedlist>
2697  *
2698  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2699  * this case, the coordinates returned will be the coordinates on
2700  * the stage before the projection is applied. This is different from
2701  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2702  *
2703  * Since: 0.6
2704  */
2705 void
2706 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2707                                        ClutterActor  *ancestor,
2708                                        ClutterVertex  verts[])
2709 {
2710   ClutterActorPrivate *priv;
2711   ClutterActorBox box;
2712   ClutterVertex vertices[4];
2713   CoglMatrix modelview;
2714
2715   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2716   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2717
2718   if (ancestor == NULL)
2719     ancestor = _clutter_actor_get_stage_internal (self);
2720
2721   /* Fallback to a NOP transform if the actor isn't parented under a
2722    * stage. */
2723   if (ancestor == NULL)
2724     ancestor = self;
2725
2726   priv = self->priv;
2727
2728   /* if the actor needs to be allocated we force a relayout, so that
2729    * we will have valid values to use in the transformations */
2730   if (priv->needs_allocation)
2731     {
2732       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2733       if (stage)
2734         _clutter_stage_maybe_relayout (stage);
2735       else
2736         {
2737           box.x1 = box.y1 = 0;
2738           /* The result isn't really meaningful in this case but at
2739            * least try to do something *vaguely* reasonable... */
2740           clutter_actor_get_size (self, &box.x2, &box.y2);
2741         }
2742     }
2743
2744   clutter_actor_get_allocation_box (self, &box);
2745
2746   vertices[0].x = box.x1;
2747   vertices[0].y = box.y1;
2748   vertices[0].z = 0;
2749   vertices[1].x = box.x2;
2750   vertices[1].y = box.y1;
2751   vertices[1].z = 0;
2752   vertices[2].x = box.x1;
2753   vertices[2].y = box.y2;
2754   vertices[2].z = 0;
2755   vertices[3].x = box.x2;
2756   vertices[3].y = box.y2;
2757   vertices[3].z = 0;
2758
2759   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2760                                                      &modelview);
2761
2762   cogl_matrix_transform_points (&modelview,
2763                                 3,
2764                                 sizeof (ClutterVertex),
2765                                 vertices,
2766                                 sizeof (ClutterVertex),
2767                                 vertices,
2768                                 4);
2769 }
2770
2771 /**
2772  * clutter_actor_get_abs_allocation_vertices:
2773  * @self: A #ClutterActor
2774  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2775  *   of 4 #ClutterVertex where to store the result.
2776  *
2777  * Calculates the transformed screen coordinates of the four corners of
2778  * the actor; the returned vertices relate to the #ClutterActorBox
2779  * coordinates  as follows:
2780  * <itemizedlist>
2781  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2782  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2783  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2784  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2785  * </itemizedlist>
2786  *
2787  * Since: 0.4
2788  */
2789 void
2790 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2791                                            ClutterVertex  verts[])
2792 {
2793   ClutterActorPrivate *priv;
2794   ClutterActorBox actor_space_allocation;
2795
2796   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2797
2798   priv = self->priv;
2799
2800   /* if the actor needs to be allocated we force a relayout, so that
2801    * the actor allocation box will be valid for
2802    * _clutter_actor_transform_and_project_box()
2803    */
2804   if (priv->needs_allocation)
2805     {
2806       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2807       /* There's nothing meaningful we can do now */
2808       if (!stage)
2809         return;
2810
2811       _clutter_stage_maybe_relayout (stage);
2812     }
2813
2814   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2815    * own coordinate space... */
2816   actor_space_allocation.x1 = 0;
2817   actor_space_allocation.y1 = 0;
2818   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2819   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2820   _clutter_actor_transform_and_project_box (self,
2821                                             &actor_space_allocation,
2822                                             verts);
2823 }
2824
2825 static void
2826 clutter_actor_real_apply_transform (ClutterActor *self,
2827                                     CoglMatrix   *matrix)
2828 {
2829   ClutterActorPrivate *priv = self->priv;
2830
2831   if (!priv->transform_valid)
2832     {
2833       CoglMatrix *transform = &priv->transform;
2834       const ClutterTransformInfo *info;
2835
2836       info = _clutter_actor_get_transform_info_or_defaults (self);
2837
2838       cogl_matrix_init_identity (transform);
2839
2840       cogl_matrix_translate (transform,
2841                              priv->allocation.x1,
2842                              priv->allocation.y1,
2843                              0.0);
2844
2845       if (info->depth)
2846         cogl_matrix_translate (transform, 0, 0, info->depth);
2847
2848       /*
2849        * because the rotation involves translations, we must scale
2850        * before applying the rotations (if we apply the scale after
2851        * the rotations, the translations included in the rotation are
2852        * not scaled and so the entire object will move on the screen
2853        * as a result of rotating it).
2854        */
2855       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2856         {
2857           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2858                                         &info->scale_center,
2859                                         cogl_matrix_scale (transform,
2860                                                            info->scale_x,
2861                                                            info->scale_y,
2862                                                            1.0));
2863         }
2864
2865       if (info->rz_angle)
2866         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2867                                       &info->rz_center,
2868                                       cogl_matrix_rotate (transform,
2869                                                           info->rz_angle,
2870                                                           0, 0, 1.0));
2871
2872       if (info->ry_angle)
2873         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2874                                       &info->ry_center,
2875                                       cogl_matrix_rotate (transform,
2876                                                           info->ry_angle,
2877                                                           0, 1.0, 0));
2878
2879       if (info->rx_angle)
2880         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2881                                       &info->rx_center,
2882                                       cogl_matrix_rotate (transform,
2883                                                           info->rx_angle,
2884                                                           1.0, 0, 0));
2885
2886       if (!clutter_anchor_coord_is_zero (&info->anchor))
2887         {
2888           gfloat x, y, z;
2889
2890           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2891           cogl_matrix_translate (transform, -x, -y, -z);
2892         }
2893
2894       priv->transform_valid = TRUE;
2895     }
2896
2897   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2898 }
2899
2900 /* Applies the transforms associated with this actor to the given
2901  * matrix. */
2902 void
2903 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2904                                           CoglMatrix *matrix)
2905 {
2906   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2907 }
2908
2909 /*
2910  * clutter_actor_apply_relative_transformation_matrix:
2911  * @self: The actor whose coordinate space you want to transform from.
2912  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2913  *            or %NULL if you want to transform all the way to eye coordinates.
2914  * @matrix: A #CoglMatrix to apply the transformation too.
2915  *
2916  * This multiplies a transform with @matrix that will transform coordinates
2917  * from the coordinate space of @self into the coordinate space of @ancestor.
2918  *
2919  * For example if you need a matrix that can transform the local actor
2920  * coordinates of @self into stage coordinates you would pass the actor's stage
2921  * pointer as the @ancestor.
2922  *
2923  * If you pass %NULL then the transformation will take you all the way through
2924  * to eye coordinates. This can be useful if you want to extract the entire
2925  * modelview transform that Clutter applies before applying the projection
2926  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2927  * using cogl_set_modelview_matrix() for example then you would want a matrix
2928  * that transforms into eye coordinates.
2929  *
2930  * <note>This function doesn't initialize the given @matrix, it simply
2931  * multiplies the requested transformation matrix with the existing contents of
2932  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2933  * before calling this function, or you can use
2934  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2935  */
2936 void
2937 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2938                                                      ClutterActor *ancestor,
2939                                                      CoglMatrix *matrix)
2940 {
2941   ClutterActor *parent;
2942
2943   /* Note we terminate before ever calling stage->apply_transform()
2944    * since that would conceptually be relative to the underlying
2945    * window OpenGL coordinates so we'd need a special @ancestor
2946    * value to represent the fake parent of the stage. */
2947   if (self == ancestor)
2948     return;
2949
2950   parent = clutter_actor_get_parent (self);
2951
2952   if (parent != NULL)
2953     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2954                                                          matrix);
2955
2956   _clutter_actor_apply_modelview_transform (self, matrix);
2957 }
2958
2959 static void
2960 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2961                                        ClutterPaintVolume *pv,
2962                                        const char *label,
2963                                        const CoglColor *color)
2964 {
2965   static CoglPipeline *outline = NULL;
2966   CoglPrimitive *prim;
2967   ClutterVertex line_ends[12 * 2];
2968   int n_vertices;
2969   CoglContext *ctx =
2970     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2971   /* XXX: at some point we'll query this from the stage but we can't
2972    * do that until the osx backend uses Cogl natively. */
2973   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2974
2975   if (outline == NULL)
2976     outline = cogl_pipeline_new (ctx);
2977
2978   _clutter_paint_volume_complete (pv);
2979
2980   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2981
2982   /* Front face */
2983   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2984   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2985   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2986   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2987
2988   if (!pv->is_2d)
2989     {
2990       /* Back face */
2991       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2992       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2993       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2994       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2995
2996       /* Lines connecting front face to back face */
2997       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2998       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2999       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3000       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3001     }
3002
3003   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3004                                 n_vertices,
3005                                 (CoglVertexP3 *)line_ends);
3006
3007   cogl_pipeline_set_color (outline, color);
3008   cogl_framebuffer_draw_primitive (fb, outline, prim);
3009   cogl_object_unref (prim);
3010
3011   if (label)
3012     {
3013       PangoLayout *layout;
3014       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3015       pango_layout_set_text (layout, label, -1);
3016       cogl_pango_render_layout (layout,
3017                                 pv->vertices[0].x,
3018                                 pv->vertices[0].y,
3019                                 color,
3020                                 0);
3021       g_object_unref (layout);
3022     }
3023 }
3024
3025 static void
3026 _clutter_actor_draw_paint_volume (ClutterActor *self)
3027 {
3028   ClutterPaintVolume *pv;
3029   CoglColor color;
3030
3031   pv = _clutter_actor_get_paint_volume_mutable (self);
3032   if (!pv)
3033     {
3034       gfloat width, height;
3035       ClutterPaintVolume fake_pv;
3036
3037       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3038       _clutter_paint_volume_init_static (&fake_pv, stage);
3039
3040       clutter_actor_get_size (self, &width, &height);
3041       clutter_paint_volume_set_width (&fake_pv, width);
3042       clutter_paint_volume_set_height (&fake_pv, height);
3043
3044       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3045       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3046                                              _clutter_actor_get_debug_name (self),
3047                                              &color);
3048
3049       clutter_paint_volume_free (&fake_pv);
3050     }
3051   else
3052     {
3053       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3054       _clutter_actor_draw_paint_volume_full (self, pv,
3055                                              _clutter_actor_get_debug_name (self),
3056                                              &color);
3057     }
3058 }
3059
3060 static void
3061 _clutter_actor_paint_cull_result (ClutterActor *self,
3062                                   gboolean success,
3063                                   ClutterCullResult result)
3064 {
3065   ClutterPaintVolume *pv;
3066   CoglColor color;
3067
3068   if (success)
3069     {
3070       if (result == CLUTTER_CULL_RESULT_IN)
3071         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3072       else if (result == CLUTTER_CULL_RESULT_OUT)
3073         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3074       else
3075         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3076     }
3077   else
3078     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3079
3080   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3081     _clutter_actor_draw_paint_volume_full (self, pv,
3082                                            _clutter_actor_get_debug_name (self),
3083                                            &color);
3084   else
3085     {
3086       PangoLayout *layout;
3087       char *label =
3088         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3089       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3090       cogl_set_source_color (&color);
3091
3092       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3093       pango_layout_set_text (layout, label, -1);
3094       cogl_pango_render_layout (layout,
3095                                 0,
3096                                 0,
3097                                 &color,
3098                                 0);
3099       g_free (label);
3100       g_object_unref (layout);
3101     }
3102 }
3103
3104 static int clone_paint_level = 0;
3105
3106 void
3107 _clutter_actor_push_clone_paint (void)
3108 {
3109   clone_paint_level++;
3110 }
3111
3112 void
3113 _clutter_actor_pop_clone_paint (void)
3114 {
3115   clone_paint_level--;
3116 }
3117
3118 static gboolean
3119 in_clone_paint (void)
3120 {
3121   return clone_paint_level > 0;
3122 }
3123
3124 /* Returns TRUE if the actor can be ignored */
3125 /* FIXME: we should return a ClutterCullResult, and
3126  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3127  * means there's no point in trying to cull descendants of the current
3128  * node. */
3129 static gboolean
3130 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3131 {
3132   ClutterActorPrivate *priv = self->priv;
3133   ClutterActor *stage;
3134   const ClutterPlane *stage_clip;
3135
3136   if (!priv->last_paint_volume_valid)
3137     {
3138       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3139                     "->last_paint_volume_valid == FALSE",
3140                     _clutter_actor_get_debug_name (self));
3141       return FALSE;
3142     }
3143
3144   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3145     return FALSE;
3146
3147   stage = _clutter_actor_get_stage_internal (self);
3148   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3149   if (G_UNLIKELY (!stage_clip))
3150     {
3151       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3152                     "No stage clip set",
3153                     _clutter_actor_get_debug_name (self));
3154       return FALSE;
3155     }
3156
3157   if (cogl_get_draw_framebuffer () !=
3158       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3159     {
3160       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3161                     "Current framebuffer doesn't correspond to stage",
3162                     _clutter_actor_get_debug_name (self));
3163       return FALSE;
3164     }
3165
3166   *result_out =
3167     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3168   return TRUE;
3169 }
3170
3171 static void
3172 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3173 {
3174   ClutterActorPrivate *priv = self->priv;
3175   const ClutterPaintVolume *pv;
3176
3177   if (priv->last_paint_volume_valid)
3178     {
3179       clutter_paint_volume_free (&priv->last_paint_volume);
3180       priv->last_paint_volume_valid = FALSE;
3181     }
3182
3183   pv = clutter_actor_get_paint_volume (self);
3184   if (!pv)
3185     {
3186       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3187                     "Actor failed to report a paint volume",
3188                     _clutter_actor_get_debug_name (self));
3189       return;
3190     }
3191
3192   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3193
3194   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3195                                             NULL); /* eye coordinates */
3196
3197   priv->last_paint_volume_valid = TRUE;
3198 }
3199
3200 static inline gboolean
3201 actor_has_shader_data (ClutterActor *self)
3202 {
3203   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3204 }
3205
3206 guint32
3207 _clutter_actor_get_pick_id (ClutterActor *self)
3208 {
3209   if (self->priv->pick_id < 0)
3210     return 0;
3211
3212   return self->priv->pick_id;
3213 }
3214
3215 /* This is the same as clutter_actor_add_effect except that it doesn't
3216    queue a redraw and it doesn't notify on the effect property */
3217 static void
3218 _clutter_actor_add_effect_internal (ClutterActor  *self,
3219                                     ClutterEffect *effect)
3220 {
3221   ClutterActorPrivate *priv = self->priv;
3222
3223   if (priv->effects == NULL)
3224     {
3225       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3226       priv->effects->actor = self;
3227     }
3228
3229   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3230 }
3231
3232 /* This is the same as clutter_actor_remove_effect except that it doesn't
3233    queue a redraw and it doesn't notify on the effect property */
3234 static void
3235 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3236                                        ClutterEffect *effect)
3237 {
3238   ClutterActorPrivate *priv = self->priv;
3239
3240   if (priv->effects == NULL)
3241     return;
3242
3243   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3244
3245   if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3246     g_clear_object (&priv->effects);
3247 }
3248
3249 static gboolean
3250 needs_flatten_effect (ClutterActor *self)
3251 {
3252   ClutterActorPrivate *priv = self->priv;
3253
3254   if (G_UNLIKELY (clutter_paint_debug_flags &
3255                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3256     return FALSE;
3257
3258   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3259     return TRUE;
3260   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3261     {
3262       if (clutter_actor_get_paint_opacity (self) < 255 &&
3263           clutter_actor_has_overlaps (self))
3264         return TRUE;
3265     }
3266
3267   return FALSE;
3268 }
3269
3270 static void
3271 add_or_remove_flatten_effect (ClutterActor *self)
3272 {
3273   ClutterActorPrivate *priv = self->priv;
3274
3275   /* Add or remove the flatten effect depending on the
3276      offscreen-redirect property. */
3277   if (needs_flatten_effect (self))
3278     {
3279       if (priv->flatten_effect == NULL)
3280         {
3281           ClutterActorMeta *actor_meta;
3282           gint priority;
3283
3284           priv->flatten_effect = _clutter_flatten_effect_new ();
3285           /* Keep a reference to the effect so that we can queue
3286              redraws from it */
3287           g_object_ref_sink (priv->flatten_effect);
3288
3289           /* Set the priority of the effect to high so that it will
3290              always be applied to the actor first. It uses an internal
3291              priority so that it won't be visible to applications */
3292           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3293           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3294           _clutter_actor_meta_set_priority (actor_meta, priority);
3295
3296           /* This will add the effect without queueing a redraw */
3297           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3298         }
3299     }
3300   else
3301     {
3302       if (priv->flatten_effect != NULL)
3303         {
3304           /* Destroy the effect so that it will lose its fbo cache of
3305              the actor */
3306           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3307           g_clear_object (&priv->flatten_effect);
3308         }
3309     }
3310 }
3311
3312 static void
3313 clutter_actor_real_paint (ClutterActor *actor)
3314 {
3315   ClutterActorPrivate *priv = actor->priv;
3316   ClutterActor *iter;
3317
3318   for (iter = priv->first_child;
3319        iter != NULL;
3320        iter = iter->priv->next_sibling)
3321     {
3322       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3323                     _clutter_actor_get_debug_name (iter),
3324                     _clutter_actor_get_debug_name (actor),
3325                     iter->priv->allocation.x1,
3326                     iter->priv->allocation.y1,
3327                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3328                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3329
3330       clutter_actor_paint (iter);
3331     }
3332 }
3333
3334 static gboolean
3335 clutter_actor_paint_node (ClutterActor     *actor,
3336                           ClutterPaintNode *root)
3337 {
3338   ClutterActorPrivate *priv = actor->priv;
3339
3340   if (root == NULL)
3341     return FALSE;
3342
3343   if (priv->bg_color_set &&
3344       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3345     {
3346       ClutterPaintNode *node;
3347       ClutterColor bg_color;
3348       ClutterActorBox box;
3349
3350       box.x1 = 0.f;
3351       box.y1 = 0.f;
3352       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3353       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3354
3355       bg_color = priv->bg_color;
3356       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3357                      * priv->bg_color.alpha
3358                      / 255;
3359
3360       node = clutter_color_node_new (&bg_color);
3361       clutter_paint_node_set_name (node, "backgroundColor");
3362       clutter_paint_node_add_rectangle (node, &box);
3363       clutter_paint_node_add_child (root, node);
3364       clutter_paint_node_unref (node);
3365     }
3366
3367   if (priv->content != NULL)
3368     _clutter_content_paint_content (priv->content, actor, root);
3369
3370   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3371     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3372
3373   if (clutter_paint_node_get_n_children (root) == 0)
3374     return FALSE;
3375
3376 #ifdef CLUTTER_ENABLE_DEBUG
3377   if (CLUTTER_HAS_DEBUG (PAINT))
3378     {
3379       /* dump the tree only if we have one */
3380       _clutter_paint_node_dump_tree (root);
3381     }
3382 #endif /* CLUTTER_ENABLE_DEBUG */
3383
3384   _clutter_paint_node_paint (root);
3385
3386 #if 0
3387   /* XXX: Uncomment this when we disable emitting the paint signal */
3388   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3389 #endif
3390
3391   return TRUE;
3392 }
3393
3394 /**
3395  * clutter_actor_paint:
3396  * @self: A #ClutterActor
3397  *
3398  * Renders the actor to display.
3399  *
3400  * This function should not be called directly by applications.
3401  * Call clutter_actor_queue_redraw() to queue paints, instead.
3402  *
3403  * This function is context-aware, and will either cause a
3404  * regular paint or a pick paint.
3405  *
3406  * This function will emit the #ClutterActor::paint signal or
3407  * the #ClutterActor::pick signal, depending on the context.
3408  *
3409  * This function does not paint the actor if the actor is set to 0,
3410  * unless it is performing a pick paint.
3411  */
3412 void
3413 clutter_actor_paint (ClutterActor *self)
3414 {
3415   ClutterActorPrivate *priv;
3416   ClutterPickMode pick_mode;
3417   gboolean clip_set = FALSE;
3418   gboolean shader_applied = FALSE;
3419
3420   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3421                           "Actor real-paint counter",
3422                           "Increments each time any actor is painted",
3423                           0 /* no application private data */);
3424   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3425                           "Actor pick-paint counter",
3426                           "Increments each time any actor is painted "
3427                           "for picking",
3428                           0 /* no application private data */);
3429
3430   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3431
3432   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3433     return;
3434
3435   priv = self->priv;
3436
3437   pick_mode = _clutter_context_get_pick_mode ();
3438
3439   if (pick_mode == CLUTTER_PICK_NONE)
3440     priv->propagated_one_redraw = FALSE;
3441
3442   /* It's an important optimization that we consider painting of
3443    * actors with 0 opacity to be a NOP... */
3444   if (pick_mode == CLUTTER_PICK_NONE &&
3445       /* ignore top-levels, since they might be transparent */
3446       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3447       /* Use the override opacity if its been set */
3448       ((priv->opacity_override >= 0) ?
3449        priv->opacity_override : priv->opacity) == 0)
3450     return;
3451
3452   /* if we aren't paintable (not in a toplevel with all
3453    * parents paintable) then do nothing.
3454    */
3455   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3456     return;
3457
3458   /* mark that we are in the paint process */
3459   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3460
3461   cogl_push_matrix();
3462
3463   if (priv->enable_model_view_transform)
3464     {
3465       CoglMatrix matrix;
3466
3467       /* XXX: It could be better to cache the modelview with the actor
3468        * instead of progressively building up the transformations on
3469        * the matrix stack every time we paint. */
3470       cogl_get_modelview_matrix (&matrix);
3471       _clutter_actor_apply_modelview_transform (self, &matrix);
3472
3473 #ifdef CLUTTER_ENABLE_DEBUG
3474       /* Catch when out-of-band transforms have been made by actors not as part
3475        * of an apply_transform vfunc... */
3476       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3477         {
3478           CoglMatrix expected_matrix;
3479
3480           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3481                                                              &expected_matrix);
3482
3483           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3484             {
3485               GString *buf = g_string_sized_new (1024);
3486               ClutterActor *parent;
3487
3488               parent = self;
3489               while (parent != NULL)
3490                 {
3491                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3492
3493                   if (parent->priv->parent != NULL)
3494                     g_string_append (buf, "->");
3495
3496                   parent = parent->priv->parent;
3497                 }
3498
3499               g_warning ("Unexpected transform found when painting actor "
3500                          "\"%s\". This will be caused by one of the actor's "
3501                          "ancestors (%s) using the Cogl API directly to transform "
3502                          "children instead of using ::apply_transform().",
3503                          _clutter_actor_get_debug_name (self),
3504                          buf->str);
3505
3506               g_string_free (buf, TRUE);
3507             }
3508         }
3509 #endif /* CLUTTER_ENABLE_DEBUG */
3510
3511       cogl_set_modelview_matrix (&matrix);
3512     }
3513
3514   if (priv->has_clip)
3515     {
3516       cogl_clip_push_rectangle (priv->clip.x,
3517                                 priv->clip.y,
3518                                 priv->clip.x + priv->clip.width,
3519                                 priv->clip.y + priv->clip.height);
3520       clip_set = TRUE;
3521     }
3522   else if (priv->clip_to_allocation)
3523     {
3524       gfloat width, height;
3525
3526       width  = priv->allocation.x2 - priv->allocation.x1;
3527       height = priv->allocation.y2 - priv->allocation.y1;
3528
3529       cogl_clip_push_rectangle (0, 0, width, height);
3530       clip_set = TRUE;
3531     }
3532
3533   if (pick_mode == CLUTTER_PICK_NONE)
3534     {
3535       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3536
3537       /* We check whether we need to add the flatten effect before
3538          each paint so that we can avoid having a mechanism for
3539          applications to notify when the value of the
3540          has_overlaps virtual changes. */
3541       add_or_remove_flatten_effect (self);
3542     }
3543   else
3544     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3545
3546   /* We save the current paint volume so that the next time the
3547    * actor queues a redraw we can constrain the redraw to just
3548    * cover the union of the new bounding box and the old.
3549    *
3550    * We also fetch the current paint volume to perform culling so
3551    * we can avoid painting actors outside the current clip region.
3552    *
3553    * If we are painting inside a clone, we should neither update
3554    * the paint volume or use it to cull painting, since the paint
3555    * box represents the location of the source actor on the
3556    * screen.
3557    *
3558    * XXX: We are starting to do a lot of vertex transforms on
3559    * the CPU in a typical paint, so at some point we should
3560    * audit these and consider caching some things.
3561    *
3562    * NB: We don't perform culling while picking at this point because
3563    * clutter-stage.c doesn't setup the clipping planes appropriately.
3564    *
3565    * NB: We don't want to update the last-paint-volume during picking
3566    * because the last-paint-volume is used to determine the old screen
3567    * space location of an actor that has moved so we can know the
3568    * minimal region to redraw to clear an old view of the actor. If we
3569    * update this during picking then by the time we come around to
3570    * paint then the last-paint-volume would likely represent the new
3571    * actor position not the old.
3572    */
3573   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3574     {
3575       gboolean success;
3576       /* annoyingly gcc warns if uninitialized even though
3577        * the initialization is redundant :-( */
3578       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3579
3580       if (G_LIKELY ((clutter_paint_debug_flags &
3581                      (CLUTTER_DEBUG_DISABLE_CULLING |
3582                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3583                     (CLUTTER_DEBUG_DISABLE_CULLING |
3584                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3585         _clutter_actor_update_last_paint_volume (self);
3586
3587       success = cull_actor (self, &result);
3588
3589       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3590         _clutter_actor_paint_cull_result (self, success, result);
3591       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3592         goto done;
3593     }
3594
3595   if (priv->effects == NULL)
3596     {
3597       if (pick_mode == CLUTTER_PICK_NONE &&
3598           actor_has_shader_data (self))
3599         {
3600           _clutter_actor_shader_pre_paint (self, FALSE);
3601           shader_applied = TRUE;
3602         }
3603
3604       priv->next_effect_to_paint = NULL;
3605     }
3606   else
3607     priv->next_effect_to_paint =
3608       _clutter_meta_group_peek_metas (priv->effects);
3609
3610   clutter_actor_continue_paint (self);
3611
3612   if (shader_applied)
3613     _clutter_actor_shader_post_paint (self);
3614
3615   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3616                   pick_mode == CLUTTER_PICK_NONE))
3617     _clutter_actor_draw_paint_volume (self);
3618
3619 done:
3620   /* If we make it here then the actor has run through a complete
3621      paint run including all the effects so it's no longer dirty */
3622   if (pick_mode == CLUTTER_PICK_NONE)
3623     priv->is_dirty = FALSE;
3624
3625   if (clip_set)
3626     cogl_clip_pop();
3627
3628   cogl_pop_matrix();
3629
3630   /* paint sequence complete */
3631   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3632 }
3633
3634 /**
3635  * clutter_actor_continue_paint:
3636  * @self: A #ClutterActor
3637  *
3638  * Run the next stage of the paint sequence. This function should only
3639  * be called within the implementation of the ‘run’ virtual of a
3640  * #ClutterEffect. It will cause the run method of the next effect to
3641  * be applied, or it will paint the actual actor if the current effect
3642  * is the last effect in the chain.
3643  *
3644  * Since: 1.8
3645  */
3646 void
3647 clutter_actor_continue_paint (ClutterActor *self)
3648 {
3649   ClutterActorPrivate *priv;
3650
3651   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3652   /* This should only be called from with in the ‘run’ implementation
3653      of a ClutterEffect */
3654   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3655
3656   priv = self->priv;
3657
3658   /* Skip any effects that are disabled */
3659   while (priv->next_effect_to_paint &&
3660          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3661     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3662
3663   /* If this has come from the last effect then we'll just paint the
3664      actual actor */
3665   if (priv->next_effect_to_paint == NULL)
3666     {
3667       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3668         {
3669           ClutterPaintNode *dummy;
3670
3671           /* XXX - this will go away in 2.0, when we can get rid of this
3672            * stuff and switch to a pure retained render tree of PaintNodes
3673            * for the entire frame, starting from the Stage; the paint()
3674            * virtual function can then be called directly.
3675            */
3676           dummy = _clutter_dummy_node_new (self);
3677           clutter_paint_node_set_name (dummy, "Root");
3678
3679           /* XXX - for 1.12, we use the return value of paint_node() to
3680            * decide whether we should emit the ::paint signal.
3681            */
3682           clutter_actor_paint_node (self, dummy);
3683           clutter_paint_node_unref (dummy);
3684
3685           g_signal_emit (self, actor_signals[PAINT], 0);
3686         }
3687       else
3688         {
3689           ClutterColor col = { 0, };
3690
3691           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3692
3693           /* Actor will then paint silhouette of itself in supplied
3694            * color.  See clutter_stage_get_actor_at_pos() for where
3695            * picking is enabled.
3696            */
3697           g_signal_emit (self, actor_signals[PICK], 0, &col);
3698         }
3699     }
3700   else
3701     {
3702       ClutterEffect *old_current_effect;
3703       ClutterEffectPaintFlags run_flags = 0;
3704
3705       /* Cache the current effect so that we can put it back before
3706          returning */
3707       old_current_effect = priv->current_effect;
3708
3709       priv->current_effect = priv->next_effect_to_paint->data;
3710       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3711
3712       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3713         {
3714           if (priv->is_dirty)
3715             {
3716               /* If there's an effect queued with this redraw then all
3717                  effects up to that one will be considered dirty. It
3718                  is expected the queued effect will paint the cached
3719                  image and not call clutter_actor_continue_paint again
3720                  (although it should work ok if it does) */
3721               if (priv->effect_to_redraw == NULL ||
3722                   priv->current_effect != priv->effect_to_redraw)
3723                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3724             }
3725
3726           _clutter_effect_paint (priv->current_effect, run_flags);
3727         }
3728       else
3729         {
3730           /* We can't determine when an actor has been modified since
3731              its last pick so lets just assume it has always been
3732              modified */
3733           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3734
3735           _clutter_effect_pick (priv->current_effect, run_flags);
3736         }
3737
3738       priv->current_effect = old_current_effect;
3739     }
3740 }
3741
3742 static ClutterActorTraverseVisitFlags
3743 invalidate_queue_redraw_entry (ClutterActor *self,
3744                                int           depth,
3745                                gpointer      user_data)
3746 {
3747   ClutterActorPrivate *priv = self->priv;
3748
3749   if (priv->queue_redraw_entry != NULL)
3750     {
3751       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3752       priv->queue_redraw_entry = NULL;
3753     }
3754
3755   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3756 }
3757
3758 static inline void
3759 remove_child (ClutterActor *self,
3760               ClutterActor *child)
3761 {
3762   ClutterActor *prev_sibling, *next_sibling;
3763
3764   prev_sibling = child->priv->prev_sibling;
3765   next_sibling = child->priv->next_sibling;
3766
3767   if (prev_sibling != NULL)
3768     prev_sibling->priv->next_sibling = next_sibling;
3769
3770   if (next_sibling != NULL)
3771     next_sibling->priv->prev_sibling = prev_sibling;
3772
3773   if (self->priv->first_child == child)
3774     self->priv->first_child = next_sibling;
3775
3776   if (self->priv->last_child == child)
3777     self->priv->last_child = prev_sibling;
3778
3779   child->priv->parent = NULL;
3780   child->priv->prev_sibling = NULL;
3781   child->priv->next_sibling = NULL;
3782 }
3783
3784 typedef enum {
3785   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3786   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3787   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3788   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3789   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3790   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3791
3792   /* default flags for public API */
3793   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3794                                     REMOVE_CHILD_EMIT_PARENT_SET |
3795                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3796                                     REMOVE_CHILD_CHECK_STATE |
3797                                     REMOVE_CHILD_FLUSH_QUEUE |
3798                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3799
3800   /* flags for legacy/deprecated API */
3801   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3802                                     REMOVE_CHILD_FLUSH_QUEUE |
3803                                     REMOVE_CHILD_EMIT_PARENT_SET |
3804                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3805 } ClutterActorRemoveChildFlags;
3806
3807 /*< private >
3808  * clutter_actor_remove_child_internal:
3809  * @self: a #ClutterActor
3810  * @child: the child of @self that has to be removed
3811  * @flags: control the removal operations
3812  *
3813  * Removes @child from the list of children of @self.
3814  */
3815 static void
3816 clutter_actor_remove_child_internal (ClutterActor                 *self,
3817                                      ClutterActor                 *child,
3818                                      ClutterActorRemoveChildFlags  flags)
3819 {
3820   ClutterActor *old_first, *old_last;
3821   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3822   gboolean flush_queue;
3823   gboolean notify_first_last;
3824   gboolean was_mapped;
3825
3826   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3827   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3828   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3829   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3830   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3831   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3832
3833   g_object_freeze_notify (G_OBJECT (self));
3834
3835   if (destroy_meta)
3836     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3837
3838   if (check_state)
3839     {
3840       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3841
3842       /* we need to unrealize *before* we set parent_actor to NULL,
3843        * because in an unrealize method actors are dissociating from the
3844        * stage, which means they need to be able to
3845        * clutter_actor_get_stage().
3846        *
3847        * yhis should unmap and unrealize, unless we're reparenting.
3848        */
3849       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3850     }
3851   else
3852     was_mapped = FALSE;
3853
3854   if (flush_queue)
3855     {
3856       /* We take this opportunity to invalidate any queue redraw entry
3857        * associated with the actor and descendants since we won't be able to
3858        * determine the appropriate stage after this.
3859        *
3860        * we do this after we updated the mapped state because actors might
3861        * end up queueing redraws inside their mapped/unmapped virtual
3862        * functions, and if we invalidate the redraw entry we could end up
3863        * with an inconsistent state and weird memory corruption. see
3864        * bugs:
3865        *
3866        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3867        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3868        */
3869       _clutter_actor_traverse (child,
3870                                0,
3871                                invalidate_queue_redraw_entry,
3872                                NULL,
3873                                NULL);
3874     }
3875
3876   old_first = self->priv->first_child;
3877   old_last = self->priv->last_child;
3878
3879   remove_child (self, child);
3880
3881   self->priv->n_children -= 1;
3882
3883   self->priv->age += 1;
3884
3885   /* clutter_actor_reparent() will emit ::parent-set for us */
3886   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3887     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3888
3889   /* if the child was mapped then we need to relayout ourselves to account
3890    * for the removed child
3891    */
3892   if (was_mapped)
3893     clutter_actor_queue_relayout (self);
3894
3895   /* we need to emit the signal before dropping the reference */
3896   if (emit_actor_removed)
3897     g_signal_emit_by_name (self, "actor-removed", child);
3898
3899   if (notify_first_last)
3900     {
3901       if (old_first != self->priv->first_child)
3902         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3903
3904       if (old_last != self->priv->last_child)
3905         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3906     }
3907
3908   g_object_thaw_notify (G_OBJECT (self));
3909
3910   /* remove the reference we acquired in clutter_actor_add_child() */
3911   g_object_unref (child);
3912 }
3913
3914 static const ClutterTransformInfo default_transform_info = {
3915   0.0, { 0, },          /* rotation-x */
3916   0.0, { 0, },          /* rotation-y */
3917   0.0, { 0, },          /* rotation-z */
3918
3919   1.0, 1.0, { 0, },     /* scale */
3920
3921   { 0, },               /* anchor */
3922
3923   0.0,                  /* depth */
3924 };
3925
3926 /*< private >
3927  * _clutter_actor_get_transform_info_or_defaults:
3928  * @self: a #ClutterActor
3929  *
3930  * Retrieves the ClutterTransformInfo structure associated to an actor.
3931  *
3932  * If the actor does not have a ClutterTransformInfo structure associated
3933  * to it, then the default structure will be returned.
3934  *
3935  * This function should only be used for getters.
3936  *
3937  * Return value: a const pointer to the ClutterTransformInfo structure
3938  */
3939 const ClutterTransformInfo *
3940 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3941 {
3942   ClutterTransformInfo *info;
3943
3944   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3945   if (info != NULL)
3946     return info;
3947
3948   return &default_transform_info;
3949 }
3950
3951 static void
3952 clutter_transform_info_free (gpointer data)
3953 {
3954   if (data != NULL)
3955     g_slice_free (ClutterTransformInfo, data);
3956 }
3957
3958 /*< private >
3959  * _clutter_actor_get_transform_info:
3960  * @self: a #ClutterActor
3961  *
3962  * Retrieves a pointer to the ClutterTransformInfo structure.
3963  *
3964  * If the actor does not have a ClutterTransformInfo associated to it, one
3965  * will be created and initialized to the default values.
3966  *
3967  * This function should be used for setters.
3968  *
3969  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3970  * instead.
3971  *
3972  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3973  *   structure
3974  */
3975 ClutterTransformInfo *
3976 _clutter_actor_get_transform_info (ClutterActor *self)
3977 {
3978   ClutterTransformInfo *info;
3979
3980   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3981   if (info == NULL)
3982     {
3983       info = g_slice_new (ClutterTransformInfo);
3984
3985       *info = default_transform_info;
3986
3987       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3988                                info,
3989                                clutter_transform_info_free);
3990     }
3991
3992   return info;
3993 }
3994
3995 /*< private >
3996  * clutter_actor_set_rotation_angle_internal:
3997  * @self: a #ClutterActor
3998  * @axis: the axis of the angle to change
3999  * @angle: the angle of rotation
4000  *
4001  * Sets the rotation angle on the given axis without affecting the
4002  * rotation center point.
4003  */
4004 static inline void
4005 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
4006                                            ClutterRotateAxis  axis,
4007                                            gdouble            angle)
4008 {
4009   GObject *obj = G_OBJECT (self);
4010   ClutterTransformInfo *info;
4011
4012   info = _clutter_actor_get_transform_info (self);
4013
4014   g_object_freeze_notify (obj);
4015
4016   switch (axis)
4017     {
4018     case CLUTTER_X_AXIS:
4019       info->rx_angle = angle;
4020       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4021       break;
4022
4023     case CLUTTER_Y_AXIS:
4024       info->ry_angle = angle;
4025       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4026       break;
4027
4028     case CLUTTER_Z_AXIS:
4029       info->rz_angle = angle;
4030       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4031       break;
4032     }
4033
4034   self->priv->transform_valid = FALSE;
4035
4036   g_object_thaw_notify (obj);
4037
4038   clutter_actor_queue_redraw (self);
4039 }
4040
4041 static inline void
4042 clutter_actor_set_rotation_angle (ClutterActor      *self,
4043                                   ClutterRotateAxis  axis,
4044                                   gdouble            angle)
4045 {
4046   const ClutterTransformInfo *info;
4047   const double *cur_angle_p = NULL;
4048   GParamSpec *pspec = NULL;
4049
4050   info = _clutter_actor_get_transform_info_or_defaults (self);
4051
4052   switch (axis)
4053     {
4054     case CLUTTER_X_AXIS:
4055       cur_angle_p = &info->rx_angle;
4056       pspec = obj_props[PROP_ROTATION_ANGLE_X];
4057       break;
4058
4059     case CLUTTER_Y_AXIS:
4060       cur_angle_p = &info->ry_angle;
4061       pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4062       break;
4063
4064     case CLUTTER_Z_AXIS:
4065       cur_angle_p = &info->rz_angle;
4066       pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4067       break;
4068     }
4069
4070   g_assert (pspec != NULL);
4071   g_assert (cur_angle_p != NULL);
4072
4073   if (_clutter_actor_get_transition (self, pspec) == NULL)
4074     _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4075   else
4076     _clutter_actor_update_transition (self, pspec, angle);
4077
4078   clutter_actor_queue_redraw (self);
4079 }
4080
4081 /*< private >
4082  * clutter_actor_set_rotation_center_internal:
4083  * @self: a #ClutterActor
4084  * @axis: the axis of the center to change
4085  * @center: the coordinates of the rotation center
4086  *
4087  * Sets the rotation center on the given axis without affecting the
4088  * rotation angle.
4089  */
4090 static inline void
4091 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4092                                             ClutterRotateAxis    axis,
4093                                             const ClutterVertex *center)
4094 {
4095   GObject *obj = G_OBJECT (self);
4096   ClutterTransformInfo *info;
4097   ClutterVertex v = { 0, 0, 0 };
4098
4099   info = _clutter_actor_get_transform_info (self);
4100
4101   if (center != NULL)
4102     v = *center;
4103
4104   g_object_freeze_notify (obj);
4105
4106   switch (axis)
4107     {
4108     case CLUTTER_X_AXIS:
4109       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4110       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4111       break;
4112
4113     case CLUTTER_Y_AXIS:
4114       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4115       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4116       break;
4117
4118     case CLUTTER_Z_AXIS:
4119       /* if the previously set rotation center was fractional, then
4120        * setting explicit coordinates will have to notify the
4121        * :rotation-center-z-gravity property as well
4122        */
4123       if (info->rz_center.is_fractional)
4124         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4125
4126       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4127       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4128       break;
4129     }
4130
4131   self->priv->transform_valid = FALSE;
4132
4133   g_object_thaw_notify (obj);
4134
4135   clutter_actor_queue_redraw (self);
4136 }
4137
4138 static void
4139 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4140                                          double factor,
4141                                          GParamSpec *pspec)
4142 {
4143   GObject *obj = G_OBJECT (self);
4144   ClutterTransformInfo *info;
4145
4146   info = _clutter_actor_get_transform_info (self);
4147
4148   if (pspec == obj_props[PROP_SCALE_X])
4149     info->scale_x = factor;
4150   else
4151     info->scale_y = factor;
4152
4153   self->priv->transform_valid = FALSE;
4154   clutter_actor_queue_redraw (self);
4155   g_object_notify_by_pspec (obj, pspec);
4156 }
4157
4158 static inline void
4159 clutter_actor_set_scale_factor (ClutterActor      *self,
4160                                 ClutterRotateAxis  axis,
4161                                 gdouble            factor)
4162 {
4163   const ClutterTransformInfo *info;
4164   const double *scale_p = NULL;
4165   GParamSpec *pspec = NULL;
4166
4167   info = _clutter_actor_get_transform_info_or_defaults (self);
4168
4169   switch (axis)
4170     {
4171     case CLUTTER_X_AXIS:
4172       pspec = obj_props[PROP_SCALE_X];
4173       scale_p = &info->scale_x;
4174       break;
4175
4176     case CLUTTER_Y_AXIS:
4177       pspec = obj_props[PROP_SCALE_Y];
4178       scale_p = &info->scale_y;
4179       break;
4180
4181     case CLUTTER_Z_AXIS:
4182       break;
4183     }
4184
4185   g_assert (pspec != NULL);
4186   g_assert (scale_p != NULL);
4187
4188   if (_clutter_actor_get_transition (self, pspec) == NULL)
4189     _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4190   else
4191     _clutter_actor_update_transition (self, pspec, factor);
4192
4193   clutter_actor_queue_redraw (self);
4194 }
4195
4196 static inline void
4197 clutter_actor_set_scale_center (ClutterActor      *self,
4198                                 ClutterRotateAxis  axis,
4199                                 gfloat             coord)
4200 {
4201   GObject *obj = G_OBJECT (self);
4202   ClutterTransformInfo *info;
4203   gfloat center_x, center_y;
4204
4205   info = _clutter_actor_get_transform_info (self);
4206
4207   g_object_freeze_notify (obj);
4208
4209   /* get the current scale center coordinates */
4210   clutter_anchor_coord_get_units (self, &info->scale_center,
4211                                   &center_x,
4212                                   &center_y,
4213                                   NULL);
4214
4215   /* we need to notify this too, because setting explicit coordinates will
4216    * change the gravity as a side effect
4217    */
4218   if (info->scale_center.is_fractional)
4219     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4220
4221   switch (axis)
4222     {
4223     case CLUTTER_X_AXIS:
4224       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4225       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4226       break;
4227
4228     case CLUTTER_Y_AXIS:
4229       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4230       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4231       break;
4232
4233     default:
4234       g_assert_not_reached ();
4235     }
4236
4237   self->priv->transform_valid = FALSE;
4238
4239   clutter_actor_queue_redraw (self);
4240
4241   g_object_thaw_notify (obj);
4242 }
4243
4244 static inline void
4245 clutter_actor_set_scale_gravity (ClutterActor   *self,
4246                                  ClutterGravity  gravity)
4247 {
4248   ClutterTransformInfo *info;
4249   GObject *obj;
4250
4251   info = _clutter_actor_get_transform_info (self);
4252   obj = G_OBJECT (self);
4253
4254   if (gravity == CLUTTER_GRAVITY_NONE)
4255     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4256   else
4257     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4258
4259   self->priv->transform_valid = FALSE;
4260
4261   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4262   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4263   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4264
4265   clutter_actor_queue_redraw (self);
4266 }
4267
4268 static inline void
4269 clutter_actor_set_anchor_coord (ClutterActor      *self,
4270                                 ClutterRotateAxis  axis,
4271                                 gfloat             coord)
4272 {
4273   GObject *obj = G_OBJECT (self);
4274   ClutterTransformInfo *info;
4275   gfloat anchor_x, anchor_y;
4276
4277   info = _clutter_actor_get_transform_info (self);
4278
4279   g_object_freeze_notify (obj);
4280
4281   clutter_anchor_coord_get_units (self, &info->anchor,
4282                                   &anchor_x,
4283                                   &anchor_y,
4284                                   NULL);
4285
4286   if (info->anchor.is_fractional)
4287     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4288
4289   switch (axis)
4290     {
4291     case CLUTTER_X_AXIS:
4292       clutter_anchor_coord_set_units (&info->anchor,
4293                                       coord,
4294                                       anchor_y,
4295                                       0.0);
4296       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4297       break;
4298
4299     case CLUTTER_Y_AXIS:
4300       clutter_anchor_coord_set_units (&info->anchor,
4301                                       anchor_x,
4302                                       coord,
4303                                       0.0);
4304       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4305       break;
4306
4307     default:
4308       g_assert_not_reached ();
4309     }
4310
4311   self->priv->transform_valid = FALSE;
4312
4313   clutter_actor_queue_redraw (self);
4314
4315   g_object_thaw_notify (obj);
4316 }
4317
4318 static void
4319 clutter_actor_set_property (GObject      *object,
4320                             guint         prop_id,
4321                             const GValue *value,
4322                             GParamSpec   *pspec)
4323 {
4324   ClutterActor *actor = CLUTTER_ACTOR (object);
4325   ClutterActorPrivate *priv = actor->priv;
4326
4327   switch (prop_id)
4328     {
4329     case PROP_X:
4330       clutter_actor_set_x (actor, g_value_get_float (value));
4331       break;
4332
4333     case PROP_Y:
4334       clutter_actor_set_y (actor, g_value_get_float (value));
4335       break;
4336
4337     case PROP_WIDTH:
4338       clutter_actor_set_width (actor, g_value_get_float (value));
4339       break;
4340
4341     case PROP_HEIGHT:
4342       clutter_actor_set_height (actor, g_value_get_float (value));
4343       break;
4344
4345     case PROP_FIXED_X:
4346       clutter_actor_set_x (actor, g_value_get_float (value));
4347       break;
4348
4349     case PROP_FIXED_Y:
4350       clutter_actor_set_y (actor, g_value_get_float (value));
4351       break;
4352
4353     case PROP_FIXED_POSITION_SET:
4354       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4355       break;
4356
4357     case PROP_MIN_WIDTH:
4358       clutter_actor_set_min_width (actor, g_value_get_float (value));
4359       break;
4360
4361     case PROP_MIN_HEIGHT:
4362       clutter_actor_set_min_height (actor, g_value_get_float (value));
4363       break;
4364
4365     case PROP_NATURAL_WIDTH:
4366       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4367       break;
4368
4369     case PROP_NATURAL_HEIGHT:
4370       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4371       break;
4372
4373     case PROP_MIN_WIDTH_SET:
4374       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4375       break;
4376
4377     case PROP_MIN_HEIGHT_SET:
4378       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4379       break;
4380
4381     case PROP_NATURAL_WIDTH_SET:
4382       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4383       break;
4384
4385     case PROP_NATURAL_HEIGHT_SET:
4386       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4387       break;
4388
4389     case PROP_REQUEST_MODE:
4390       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4391       break;
4392
4393     case PROP_DEPTH:
4394       clutter_actor_set_depth (actor, g_value_get_float (value));
4395       break;
4396
4397     case PROP_OPACITY:
4398       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4399       break;
4400
4401     case PROP_OFFSCREEN_REDIRECT:
4402       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4403       break;
4404
4405     case PROP_NAME:
4406       clutter_actor_set_name (actor, g_value_get_string (value));
4407       break;
4408
4409     case PROP_VISIBLE:
4410       if (g_value_get_boolean (value) == TRUE)
4411         clutter_actor_show (actor);
4412       else
4413         clutter_actor_hide (actor);
4414       break;
4415
4416     case PROP_SCALE_X:
4417       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4418                                       g_value_get_double (value));
4419       break;
4420
4421     case PROP_SCALE_Y:
4422       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4423                                       g_value_get_double (value));
4424       break;
4425
4426     case PROP_SCALE_CENTER_X:
4427       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4428                                       g_value_get_float (value));
4429       break;
4430
4431     case PROP_SCALE_CENTER_Y:
4432       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4433                                       g_value_get_float (value));
4434       break;
4435
4436     case PROP_SCALE_GRAVITY:
4437       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4438       break;
4439
4440     case PROP_CLIP:
4441       {
4442         const ClutterGeometry *geom = g_value_get_boxed (value);
4443
4444         clutter_actor_set_clip (actor,
4445                                 geom->x, geom->y,
4446                                 geom->width, geom->height);
4447       }
4448       break;
4449
4450     case PROP_CLIP_TO_ALLOCATION:
4451       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4452       break;
4453
4454     case PROP_REACTIVE:
4455       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4456       break;
4457
4458     case PROP_ROTATION_ANGLE_X:
4459       clutter_actor_set_rotation_angle (actor,
4460                                         CLUTTER_X_AXIS,
4461                                         g_value_get_double (value));
4462       break;
4463
4464     case PROP_ROTATION_ANGLE_Y:
4465       clutter_actor_set_rotation_angle (actor,
4466                                         CLUTTER_Y_AXIS,
4467                                         g_value_get_double (value));
4468       break;
4469
4470     case PROP_ROTATION_ANGLE_Z:
4471       clutter_actor_set_rotation_angle (actor,
4472                                         CLUTTER_Z_AXIS,
4473                                         g_value_get_double (value));
4474       break;
4475
4476     case PROP_ROTATION_CENTER_X:
4477       clutter_actor_set_rotation_center_internal (actor,
4478                                                   CLUTTER_X_AXIS,
4479                                                   g_value_get_boxed (value));
4480       break;
4481
4482     case PROP_ROTATION_CENTER_Y:
4483       clutter_actor_set_rotation_center_internal (actor,
4484                                                   CLUTTER_Y_AXIS,
4485                                                   g_value_get_boxed (value));
4486       break;
4487
4488     case PROP_ROTATION_CENTER_Z:
4489       clutter_actor_set_rotation_center_internal (actor,
4490                                                   CLUTTER_Z_AXIS,
4491                                                   g_value_get_boxed (value));
4492       break;
4493
4494     case PROP_ROTATION_CENTER_Z_GRAVITY:
4495       {
4496         const ClutterTransformInfo *info;
4497
4498         info = _clutter_actor_get_transform_info_or_defaults (actor);
4499         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4500                                                    g_value_get_enum (value));
4501       }
4502       break;
4503
4504     case PROP_ANCHOR_X:
4505       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4506                                       g_value_get_float (value));
4507       break;
4508
4509     case PROP_ANCHOR_Y:
4510       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4511                                       g_value_get_float (value));
4512       break;
4513
4514     case PROP_ANCHOR_GRAVITY:
4515       clutter_actor_set_anchor_point_from_gravity (actor,
4516                                                    g_value_get_enum (value));
4517       break;
4518
4519     case PROP_SHOW_ON_SET_PARENT:
4520       priv->show_on_set_parent = g_value_get_boolean (value);
4521       break;
4522
4523     case PROP_TEXT_DIRECTION:
4524       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4525       break;
4526
4527     case PROP_ACTIONS:
4528       clutter_actor_add_action (actor, g_value_get_object (value));
4529       break;
4530
4531     case PROP_CONSTRAINTS:
4532       clutter_actor_add_constraint (actor, g_value_get_object (value));
4533       break;
4534
4535     case PROP_EFFECT:
4536       clutter_actor_add_effect (actor, g_value_get_object (value));
4537       break;
4538
4539     case PROP_LAYOUT_MANAGER:
4540       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4541       break;
4542
4543     case PROP_X_ALIGN:
4544       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4545       break;
4546
4547     case PROP_Y_ALIGN:
4548       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4549       break;
4550
4551     case PROP_MARGIN_TOP:
4552       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4553       break;
4554
4555     case PROP_MARGIN_BOTTOM:
4556       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4557       break;
4558
4559     case PROP_MARGIN_LEFT:
4560       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4561       break;
4562
4563     case PROP_MARGIN_RIGHT:
4564       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4565       break;
4566
4567     case PROP_BACKGROUND_COLOR:
4568       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4569       break;
4570
4571     case PROP_CONTENT:
4572       clutter_actor_set_content (actor, g_value_get_object (value));
4573       break;
4574
4575     case PROP_CONTENT_GRAVITY:
4576       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4577       break;
4578
4579     case PROP_MINIFICATION_FILTER:
4580       clutter_actor_set_content_scaling_filters (actor,
4581                                                  g_value_get_enum (value),
4582                                                  actor->priv->mag_filter);
4583       break;
4584
4585     case PROP_MAGNIFICATION_FILTER:
4586       clutter_actor_set_content_scaling_filters (actor,
4587                                                  actor->priv->min_filter,
4588                                                  g_value_get_enum (value));
4589       break;
4590
4591     default:
4592       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4593       break;
4594     }
4595 }
4596
4597 static void
4598 clutter_actor_get_property (GObject    *object,
4599                             guint       prop_id,
4600                             GValue     *value,
4601                             GParamSpec *pspec)
4602 {
4603   ClutterActor *actor = CLUTTER_ACTOR (object);
4604   ClutterActorPrivate *priv = actor->priv;
4605
4606   switch (prop_id)
4607     {
4608     case PROP_X:
4609       g_value_set_float (value, clutter_actor_get_x (actor));
4610       break;
4611
4612     case PROP_Y:
4613       g_value_set_float (value, clutter_actor_get_y (actor));
4614       break;
4615
4616     case PROP_WIDTH:
4617       g_value_set_float (value, clutter_actor_get_width (actor));
4618       break;
4619
4620     case PROP_HEIGHT:
4621       g_value_set_float (value, clutter_actor_get_height (actor));
4622       break;
4623
4624     case PROP_FIXED_X:
4625       {
4626         const ClutterLayoutInfo *info;
4627
4628         info = _clutter_actor_get_layout_info_or_defaults (actor);
4629         g_value_set_float (value, info->fixed_x);
4630       }
4631       break;
4632
4633     case PROP_FIXED_Y:
4634       {
4635         const ClutterLayoutInfo *info;
4636
4637         info = _clutter_actor_get_layout_info_or_defaults (actor);
4638         g_value_set_float (value, info->fixed_y);
4639       }
4640       break;
4641
4642     case PROP_FIXED_POSITION_SET:
4643       g_value_set_boolean (value, priv->position_set);
4644       break;
4645
4646     case PROP_MIN_WIDTH:
4647       {
4648         const ClutterLayoutInfo *info;
4649
4650         info = _clutter_actor_get_layout_info_or_defaults (actor);
4651         g_value_set_float (value, info->min_width);
4652       }
4653       break;
4654
4655     case PROP_MIN_HEIGHT:
4656       {
4657         const ClutterLayoutInfo *info;
4658
4659         info = _clutter_actor_get_layout_info_or_defaults (actor);
4660         g_value_set_float (value, info->min_height);
4661       }
4662       break;
4663
4664     case PROP_NATURAL_WIDTH:
4665       {
4666         const ClutterLayoutInfo *info;
4667
4668         info = _clutter_actor_get_layout_info_or_defaults (actor);
4669         g_value_set_float (value, info->natural_width);
4670       }
4671       break;
4672
4673     case PROP_NATURAL_HEIGHT:
4674       {
4675         const ClutterLayoutInfo *info;
4676
4677         info = _clutter_actor_get_layout_info_or_defaults (actor);
4678         g_value_set_float (value, info->natural_height);
4679       }
4680       break;
4681
4682     case PROP_MIN_WIDTH_SET:
4683       g_value_set_boolean (value, priv->min_width_set);
4684       break;
4685
4686     case PROP_MIN_HEIGHT_SET:
4687       g_value_set_boolean (value, priv->min_height_set);
4688       break;
4689
4690     case PROP_NATURAL_WIDTH_SET:
4691       g_value_set_boolean (value, priv->natural_width_set);
4692       break;
4693
4694     case PROP_NATURAL_HEIGHT_SET:
4695       g_value_set_boolean (value, priv->natural_height_set);
4696       break;
4697
4698     case PROP_REQUEST_MODE:
4699       g_value_set_enum (value, priv->request_mode);
4700       break;
4701
4702     case PROP_ALLOCATION:
4703       g_value_set_boxed (value, &priv->allocation);
4704       break;
4705
4706     case PROP_DEPTH:
4707       g_value_set_float (value, clutter_actor_get_depth (actor));
4708       break;
4709
4710     case PROP_OPACITY:
4711       g_value_set_uint (value, priv->opacity);
4712       break;
4713
4714     case PROP_OFFSCREEN_REDIRECT:
4715       g_value_set_enum (value, priv->offscreen_redirect);
4716       break;
4717
4718     case PROP_NAME:
4719       g_value_set_string (value, priv->name);
4720       break;
4721
4722     case PROP_VISIBLE:
4723       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4724       break;
4725
4726     case PROP_MAPPED:
4727       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4728       break;
4729
4730     case PROP_REALIZED:
4731       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4732       break;
4733
4734     case PROP_HAS_CLIP:
4735       g_value_set_boolean (value, priv->has_clip);
4736       break;
4737
4738     case PROP_CLIP:
4739       {
4740         ClutterGeometry clip;
4741
4742         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4743         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4744         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4745         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4746
4747         g_value_set_boxed (value, &clip);
4748       }
4749       break;
4750
4751     case PROP_CLIP_TO_ALLOCATION:
4752       g_value_set_boolean (value, priv->clip_to_allocation);
4753       break;
4754
4755     case PROP_SCALE_X:
4756       {
4757         const ClutterTransformInfo *info;
4758
4759         info = _clutter_actor_get_transform_info_or_defaults (actor);
4760         g_value_set_double (value, info->scale_x);
4761       }
4762       break;
4763
4764     case PROP_SCALE_Y:
4765       {
4766         const ClutterTransformInfo *info;
4767
4768         info = _clutter_actor_get_transform_info_or_defaults (actor);
4769         g_value_set_double (value, info->scale_y);
4770       }
4771       break;
4772
4773     case PROP_SCALE_CENTER_X:
4774       {
4775         gfloat center;
4776
4777         clutter_actor_get_scale_center (actor, &center, NULL);
4778
4779         g_value_set_float (value, center);
4780       }
4781       break;
4782
4783     case PROP_SCALE_CENTER_Y:
4784       {
4785         gfloat center;
4786
4787         clutter_actor_get_scale_center (actor, NULL, &center);
4788
4789         g_value_set_float (value, center);
4790       }
4791       break;
4792
4793     case PROP_SCALE_GRAVITY:
4794       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4795       break;
4796
4797     case PROP_REACTIVE:
4798       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4799       break;
4800
4801     case PROP_ROTATION_ANGLE_X:
4802       {
4803         const ClutterTransformInfo *info;
4804
4805         info = _clutter_actor_get_transform_info_or_defaults (actor);
4806         g_value_set_double (value, info->rx_angle);
4807       }
4808       break;
4809
4810     case PROP_ROTATION_ANGLE_Y:
4811       {
4812         const ClutterTransformInfo *info;
4813
4814         info = _clutter_actor_get_transform_info_or_defaults (actor);
4815         g_value_set_double (value, info->ry_angle);
4816       }
4817       break;
4818
4819     case PROP_ROTATION_ANGLE_Z:
4820       {
4821         const ClutterTransformInfo *info;
4822
4823         info = _clutter_actor_get_transform_info_or_defaults (actor);
4824         g_value_set_double (value, info->rz_angle);
4825       }
4826       break;
4827
4828     case PROP_ROTATION_CENTER_X:
4829       {
4830         ClutterVertex center;
4831
4832         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4833                                     &center.x,
4834                                     &center.y,
4835                                     &center.z);
4836
4837         g_value_set_boxed (value, &center);
4838       }
4839       break;
4840
4841     case PROP_ROTATION_CENTER_Y:
4842       {
4843         ClutterVertex center;
4844
4845         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4846                                     &center.x,
4847                                     &center.y,
4848                                     &center.z);
4849
4850         g_value_set_boxed (value, &center);
4851       }
4852       break;
4853
4854     case PROP_ROTATION_CENTER_Z:
4855       {
4856         ClutterVertex center;
4857
4858         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4859                                     &center.x,
4860                                     &center.y,
4861                                     &center.z);
4862
4863         g_value_set_boxed (value, &center);
4864       }
4865       break;
4866
4867     case PROP_ROTATION_CENTER_Z_GRAVITY:
4868       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4869       break;
4870
4871     case PROP_ANCHOR_X:
4872       {
4873         const ClutterTransformInfo *info;
4874         gfloat anchor_x;
4875
4876         info = _clutter_actor_get_transform_info_or_defaults (actor);
4877         clutter_anchor_coord_get_units (actor, &info->anchor,
4878                                         &anchor_x,
4879                                         NULL,
4880                                         NULL);
4881         g_value_set_float (value, anchor_x);
4882       }
4883       break;
4884
4885     case PROP_ANCHOR_Y:
4886       {
4887         const ClutterTransformInfo *info;
4888         gfloat anchor_y;
4889
4890         info = _clutter_actor_get_transform_info_or_defaults (actor);
4891         clutter_anchor_coord_get_units (actor, &info->anchor,
4892                                         NULL,
4893                                         &anchor_y,
4894                                         NULL);
4895         g_value_set_float (value, anchor_y);
4896       }
4897       break;
4898
4899     case PROP_ANCHOR_GRAVITY:
4900       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4901       break;
4902
4903     case PROP_SHOW_ON_SET_PARENT:
4904       g_value_set_boolean (value, priv->show_on_set_parent);
4905       break;
4906
4907     case PROP_TEXT_DIRECTION:
4908       g_value_set_enum (value, priv->text_direction);
4909       break;
4910
4911     case PROP_HAS_POINTER:
4912       g_value_set_boolean (value, priv->has_pointer);
4913       break;
4914
4915     case PROP_LAYOUT_MANAGER:
4916       g_value_set_object (value, priv->layout_manager);
4917       break;
4918
4919     case PROP_X_ALIGN:
4920       {
4921         const ClutterLayoutInfo *info;
4922
4923         info = _clutter_actor_get_layout_info_or_defaults (actor);
4924         g_value_set_enum (value, info->x_align);
4925       }
4926       break;
4927
4928     case PROP_Y_ALIGN:
4929       {
4930         const ClutterLayoutInfo *info;
4931
4932         info = _clutter_actor_get_layout_info_or_defaults (actor);
4933         g_value_set_enum (value, info->y_align);
4934       }
4935       break;
4936
4937     case PROP_MARGIN_TOP:
4938       {
4939         const ClutterLayoutInfo *info;
4940
4941         info = _clutter_actor_get_layout_info_or_defaults (actor);
4942         g_value_set_float (value, info->margin.top);
4943       }
4944       break;
4945
4946     case PROP_MARGIN_BOTTOM:
4947       {
4948         const ClutterLayoutInfo *info;
4949
4950         info = _clutter_actor_get_layout_info_or_defaults (actor);
4951         g_value_set_float (value, info->margin.bottom);
4952       }
4953       break;
4954
4955     case PROP_MARGIN_LEFT:
4956       {
4957         const ClutterLayoutInfo *info;
4958
4959         info = _clutter_actor_get_layout_info_or_defaults (actor);
4960         g_value_set_float (value, info->margin.left);
4961       }
4962       break;
4963
4964     case PROP_MARGIN_RIGHT:
4965       {
4966         const ClutterLayoutInfo *info;
4967
4968         info = _clutter_actor_get_layout_info_or_defaults (actor);
4969         g_value_set_float (value, info->margin.right);
4970       }
4971       break;
4972
4973     case PROP_BACKGROUND_COLOR_SET:
4974       g_value_set_boolean (value, priv->bg_color_set);
4975       break;
4976
4977     case PROP_BACKGROUND_COLOR:
4978       g_value_set_boxed (value, &priv->bg_color);
4979       break;
4980
4981     case PROP_FIRST_CHILD:
4982       g_value_set_object (value, priv->first_child);
4983       break;
4984
4985     case PROP_LAST_CHILD:
4986       g_value_set_object (value, priv->last_child);
4987       break;
4988
4989     case PROP_CONTENT:
4990       g_value_set_object (value, priv->content);
4991       break;
4992
4993     case PROP_CONTENT_GRAVITY:
4994       g_value_set_enum (value, priv->content_gravity);
4995       break;
4996
4997     case PROP_CONTENT_BOX:
4998       {
4999         ClutterActorBox box = { 0, };
5000
5001         clutter_actor_get_content_box (actor, &box);
5002         g_value_set_boxed (value, &box);
5003       }
5004       break;
5005
5006     case PROP_MINIFICATION_FILTER:
5007       g_value_set_enum (value, priv->min_filter);
5008       break;
5009
5010     case PROP_MAGNIFICATION_FILTER:
5011       g_value_set_enum (value, priv->mag_filter);
5012       break;
5013
5014     default:
5015       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5016       break;
5017     }
5018 }
5019
5020 static void
5021 clutter_actor_dispose (GObject *object)
5022 {
5023   ClutterActor *self = CLUTTER_ACTOR (object);
5024   ClutterActorPrivate *priv = self->priv;
5025
5026   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5027                 priv->id,
5028                 g_type_name (G_OBJECT_TYPE (self)),
5029                 object->ref_count);
5030
5031   g_signal_emit (self, actor_signals[DESTROY], 0);
5032
5033   /* avoid recursing when called from clutter_actor_destroy() */
5034   if (priv->parent != NULL)
5035     {
5036       ClutterActor *parent = priv->parent;
5037
5038       /* go through the Container implementation unless this
5039        * is an internal child and has been marked as such.
5040        *
5041        * removing the actor from its parent will reset the
5042        * realized and mapped states.
5043        */
5044       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5045         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5046       else
5047         clutter_actor_remove_child_internal (parent, self,
5048                                              REMOVE_CHILD_LEGACY_FLAGS);
5049     }
5050
5051   /* parent must be gone at this point */
5052   g_assert (priv->parent == NULL);
5053
5054   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5055     {
5056       /* can't be mapped or realized with no parent */
5057       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5058       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5059     }
5060
5061   g_clear_object (&priv->pango_context);
5062   g_clear_object (&priv->actions);
5063   g_clear_object (&priv->constraints);
5064   g_clear_object (&priv->effects);
5065   g_clear_object (&priv->flatten_effect);
5066
5067   if (priv->layout_manager != NULL)
5068     {
5069       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5070       g_clear_object (&priv->layout_manager);
5071     }
5072
5073   if (priv->content != NULL)
5074     {
5075       _clutter_content_detached (priv->content, self);
5076       g_clear_object (&priv->content);
5077     }
5078
5079   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5080 }
5081
5082 static void
5083 clutter_actor_finalize (GObject *object)
5084 {
5085   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5086
5087   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5088                 priv->name != NULL ? priv->name : "<none>",
5089                 priv->id,
5090                 g_type_name (G_OBJECT_TYPE (object)));
5091
5092   _clutter_context_release_id (priv->id);
5093
5094   g_free (priv->name);
5095
5096   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5097 }
5098
5099
5100 /**
5101  * clutter_actor_get_accessible:
5102  * @self: a #ClutterActor
5103  *
5104  * Returns the accessible object that describes the actor to an
5105  * assistive technology.
5106  *
5107  * If no class-specific #AtkObject implementation is available for the
5108  * actor instance in question, it will inherit an #AtkObject
5109  * implementation from the first ancestor class for which such an
5110  * implementation is defined.
5111  *
5112  * The documentation of the <ulink
5113  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5114  * library contains more information about accessible objects and
5115  * their uses.
5116  *
5117  * Returns: (transfer none): the #AtkObject associated with @actor
5118  */
5119 AtkObject *
5120 clutter_actor_get_accessible (ClutterActor *self)
5121 {
5122   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5123
5124   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5125 }
5126
5127 static AtkObject *
5128 clutter_actor_real_get_accessible (ClutterActor *actor)
5129 {
5130   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5131 }
5132
5133 static AtkObject *
5134 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5135 {
5136   AtkObject *accessible;
5137
5138   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5139   if (accessible != NULL)
5140     g_object_ref (accessible);
5141
5142   return accessible;
5143 }
5144
5145 static void
5146 atk_implementor_iface_init (AtkImplementorIface *iface)
5147 {
5148   iface->ref_accessible = _clutter_actor_ref_accessible;
5149 }
5150
5151 static gboolean
5152 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5153                                            ClutterPaintVolume *volume)
5154 {
5155   ClutterActorPrivate *priv = self->priv;
5156   gboolean res = TRUE;
5157
5158   /* we start from the allocation */
5159   clutter_paint_volume_set_width (volume,
5160                                   priv->allocation.x2 - priv->allocation.x1);
5161   clutter_paint_volume_set_height (volume,
5162                                    priv->allocation.y2 - priv->allocation.y1);
5163
5164   /* if the actor has a clip set then we have a pretty definite
5165    * size for the paint volume: the actor cannot possibly paint
5166    * outside the clip region.
5167    */
5168   if (priv->clip_to_allocation)
5169     {
5170       /* the allocation has already been set, so we just flip the
5171        * return value
5172        */
5173       res = TRUE;
5174     }
5175   else
5176     {
5177       ClutterActor *child;
5178
5179       if (priv->has_clip &&
5180           priv->clip.width >= 0 &&
5181           priv->clip.height >= 0)
5182         {
5183           ClutterVertex origin;
5184
5185           origin.x = priv->clip.x;
5186           origin.y = priv->clip.y;
5187           origin.z = 0;
5188
5189           clutter_paint_volume_set_origin (volume, &origin);
5190           clutter_paint_volume_set_width (volume, priv->clip.width);
5191           clutter_paint_volume_set_height (volume, priv->clip.height);
5192
5193           res = TRUE;
5194         }
5195
5196       /* if we don't have children we just bail out here... */
5197       if (priv->n_children == 0)
5198         return res;
5199
5200       /* ...but if we have children then we ask for their paint volume in
5201        * our coordinates. if any of our children replies that it doesn't
5202        * have a paint volume, we bail out
5203        */
5204       for (child = priv->first_child;
5205            child != NULL;
5206            child = child->priv->next_sibling)
5207         {
5208           const ClutterPaintVolume *child_volume;
5209
5210           if (!CLUTTER_ACTOR_IS_MAPPED (child))
5211             continue;
5212
5213           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5214           if (child_volume == NULL)
5215             {
5216               res = FALSE;
5217               break;
5218             }
5219
5220           clutter_paint_volume_union (volume, child_volume);
5221           res = TRUE;
5222         }
5223     }
5224
5225   return res;
5226
5227 }
5228
5229 static gboolean
5230 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5231                                      ClutterPaintVolume *volume)
5232 {
5233   ClutterActorClass *klass;
5234   gboolean res;
5235
5236   klass = CLUTTER_ACTOR_GET_CLASS (self);
5237
5238   /* XXX - this thoroughly sucks, but we don't want to penalize users
5239    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5240    * redraw. This should go away in 2.0.
5241    */
5242   if (klass->paint == clutter_actor_real_paint &&
5243       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5244     {
5245       res = TRUE;
5246     }
5247   else
5248     {
5249       /* this is the default return value: we cannot know if a class
5250        * is going to paint outside its allocation, so we take the
5251        * conservative approach.
5252        */
5253       res = FALSE;
5254     }
5255
5256   /* update_default_paint_volume() should only fail if one of the children
5257    * reported an invalid, or no, paint volume
5258    */
5259   if (!clutter_actor_update_default_paint_volume (self, volume))
5260     return FALSE;
5261
5262   return res;
5263 }
5264
5265 /**
5266  * clutter_actor_get_default_paint_volume:
5267  * @self: a #ClutterActor
5268  *
5269  * Retrieves the default paint volume for @self.
5270  *
5271  * This function provides the same #ClutterPaintVolume that would be
5272  * computed by the default implementation inside #ClutterActor of the
5273  * #ClutterActorClass.get_paint_volume() virtual function.
5274  *
5275  * This function should only be used by #ClutterActor subclasses that
5276  * cannot chain up to the parent implementation when computing their
5277  * paint volume.
5278  *
5279  * Return value: (transfer none): a pointer to the default
5280  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5281  *   the actor could not compute a valid paint volume. The returned value
5282  *   is not guaranteed to be stable across multiple frames, so if you
5283  *   want to retain it, you will need to copy it using
5284  *   clutter_paint_volume_copy().
5285  *
5286  * Since: 1.10
5287  */
5288 const ClutterPaintVolume *
5289 clutter_actor_get_default_paint_volume (ClutterActor *self)
5290 {
5291   ClutterPaintVolume volume;
5292   ClutterPaintVolume *res;
5293
5294   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5295
5296   res = NULL;
5297   _clutter_paint_volume_init_static (&volume, self);
5298   if (clutter_actor_update_default_paint_volume (self, &volume))
5299     {
5300       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5301
5302       if (stage != NULL)
5303         {
5304           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5305           _clutter_paint_volume_copy_static (&volume, res);
5306         }
5307     }
5308
5309   clutter_paint_volume_free (&volume);
5310
5311   return res;
5312 }
5313
5314 static gboolean
5315 clutter_actor_real_has_overlaps (ClutterActor *self)
5316 {
5317   /* By default we'll assume that all actors need an offscreen redirect to get
5318    * the correct opacity. Actors such as ClutterTexture that would never need
5319    * an offscreen redirect can override this to return FALSE. */
5320   return TRUE;
5321 }
5322
5323 static void
5324 clutter_actor_real_destroy (ClutterActor *actor)
5325 {
5326   ClutterActorIter iter;
5327
5328   g_object_freeze_notify (G_OBJECT (actor));
5329
5330   clutter_actor_iter_init (&iter, actor);
5331   while (clutter_actor_iter_next (&iter, NULL))
5332     clutter_actor_iter_destroy (&iter);
5333
5334   g_object_thaw_notify (G_OBJECT (actor));
5335 }
5336
5337 static GObject *
5338 clutter_actor_constructor (GType gtype,
5339                            guint n_props,
5340                            GObjectConstructParam *props)
5341 {
5342   GObjectClass *gobject_class;
5343   ClutterActor *self;
5344   GObject *retval;
5345
5346   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5347   retval = gobject_class->constructor (gtype, n_props, props);
5348   self = CLUTTER_ACTOR (retval);
5349
5350   if (self->priv->layout_manager == NULL)
5351     {
5352       ClutterLayoutManager *default_layout;
5353
5354       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5355
5356       default_layout = clutter_fixed_layout_new ();
5357       clutter_actor_set_layout_manager (self, default_layout);
5358     }
5359
5360   return retval;
5361 }
5362
5363 static void
5364 clutter_actor_class_init (ClutterActorClass *klass)
5365 {
5366   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5367
5368   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5369   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5370   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5371   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5372
5373   object_class->constructor = clutter_actor_constructor;
5374   object_class->set_property = clutter_actor_set_property;
5375   object_class->get_property = clutter_actor_get_property;
5376   object_class->dispose = clutter_actor_dispose;
5377   object_class->finalize = clutter_actor_finalize;
5378
5379   klass->show = clutter_actor_real_show;
5380   klass->show_all = clutter_actor_show;
5381   klass->hide = clutter_actor_real_hide;
5382   klass->hide_all = clutter_actor_hide;
5383   klass->map = clutter_actor_real_map;
5384   klass->unmap = clutter_actor_real_unmap;
5385   klass->unrealize = clutter_actor_real_unrealize;
5386   klass->pick = clutter_actor_real_pick;
5387   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5388   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5389   klass->allocate = clutter_actor_real_allocate;
5390   klass->queue_redraw = clutter_actor_real_queue_redraw;
5391   klass->queue_relayout = clutter_actor_real_queue_relayout;
5392   klass->apply_transform = clutter_actor_real_apply_transform;
5393   klass->get_accessible = clutter_actor_real_get_accessible;
5394   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5395   klass->has_overlaps = clutter_actor_real_has_overlaps;
5396   klass->paint = clutter_actor_real_paint;
5397   klass->destroy = clutter_actor_real_destroy;
5398
5399   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5400
5401   /**
5402    * ClutterActor:x:
5403    *
5404    * X coordinate of the actor in pixels. If written, forces a fixed
5405    * position for the actor. If read, returns the fixed position if any,
5406    * otherwise the allocation if available, otherwise 0.
5407    *
5408    * The #ClutterActor:x property is animatable.
5409    */
5410   obj_props[PROP_X] =
5411     g_param_spec_float ("x",
5412                         P_("X coordinate"),
5413                         P_("X coordinate of the actor"),
5414                         -G_MAXFLOAT, G_MAXFLOAT,
5415                         0.0,
5416                         G_PARAM_READWRITE |
5417                         G_PARAM_STATIC_STRINGS |
5418                         CLUTTER_PARAM_ANIMATABLE);
5419
5420   /**
5421    * ClutterActor:y:
5422    *
5423    * Y coordinate of the actor in pixels. If written, forces a fixed
5424    * position for the actor.  If read, returns the fixed position if
5425    * any, otherwise the allocation if available, otherwise 0.
5426    *
5427    * The #ClutterActor:y property is animatable.
5428    */
5429   obj_props[PROP_Y] =
5430     g_param_spec_float ("y",
5431                         P_("Y coordinate"),
5432                         P_("Y coordinate of the actor"),
5433                         -G_MAXFLOAT, G_MAXFLOAT,
5434                         0.0,
5435                         G_PARAM_READWRITE |
5436                         G_PARAM_STATIC_STRINGS |
5437                         CLUTTER_PARAM_ANIMATABLE);
5438
5439   /**
5440    * ClutterActor:width:
5441    *
5442    * Width of the actor (in pixels). If written, forces the minimum and
5443    * natural size request of the actor to the given width. If read, returns
5444    * the allocated width if available, otherwise the width request.
5445    *
5446    * The #ClutterActor:width property is animatable.
5447    */
5448   obj_props[PROP_WIDTH] =
5449     g_param_spec_float ("width",
5450                         P_("Width"),
5451                         P_("Width of the actor"),
5452                         0.0, G_MAXFLOAT,
5453                         0.0,
5454                         G_PARAM_READWRITE |
5455                         G_PARAM_STATIC_STRINGS |
5456                         CLUTTER_PARAM_ANIMATABLE);
5457
5458   /**
5459    * ClutterActor:height:
5460    *
5461    * Height of the actor (in pixels).  If written, forces the minimum and
5462    * natural size request of the actor to the given height. If read, returns
5463    * the allocated height if available, otherwise the height request.
5464    *
5465    * The #ClutterActor:height property is animatable.
5466    */
5467   obj_props[PROP_HEIGHT] =
5468     g_param_spec_float ("height",
5469                         P_("Height"),
5470                         P_("Height of the actor"),
5471                         0.0, G_MAXFLOAT,
5472                         0.0,
5473                         G_PARAM_READWRITE |
5474                         G_PARAM_STATIC_STRINGS |
5475                         CLUTTER_PARAM_ANIMATABLE);
5476
5477   /**
5478    * ClutterActor:fixed-x:
5479    *
5480    * The fixed X position of the actor in pixels.
5481    *
5482    * Writing this property sets #ClutterActor:fixed-position-set
5483    * property as well, as a side effect
5484    *
5485    * Since: 0.8
5486    */
5487   obj_props[PROP_FIXED_X] =
5488     g_param_spec_float ("fixed-x",
5489                         P_("Fixed X"),
5490                         P_("Forced X position of the actor"),
5491                         -G_MAXFLOAT, G_MAXFLOAT,
5492                         0.0,
5493                         CLUTTER_PARAM_READWRITE);
5494
5495   /**
5496    * ClutterActor:fixed-y:
5497    *
5498    * The fixed Y position of the actor in pixels.
5499    *
5500    * Writing this property sets the #ClutterActor:fixed-position-set
5501    * property as well, as a side effect
5502    *
5503    * Since: 0.8
5504    */
5505   obj_props[PROP_FIXED_Y] =
5506     g_param_spec_float ("fixed-y",
5507                         P_("Fixed Y"),
5508                         P_("Forced Y position of the actor"),
5509                         -G_MAXFLOAT, G_MAXFLOAT,
5510                         0,
5511                         CLUTTER_PARAM_READWRITE);
5512
5513   /**
5514    * ClutterActor:fixed-position-set:
5515    *
5516    * This flag controls whether the #ClutterActor:fixed-x and
5517    * #ClutterActor:fixed-y properties are used
5518    *
5519    * Since: 0.8
5520    */
5521   obj_props[PROP_FIXED_POSITION_SET] =
5522     g_param_spec_boolean ("fixed-position-set",
5523                           P_("Fixed position set"),
5524                           P_("Whether to use fixed positioning for the actor"),
5525                           FALSE,
5526                           CLUTTER_PARAM_READWRITE);
5527
5528   /**
5529    * ClutterActor:min-width:
5530    *
5531    * A forced minimum width request for the actor, in pixels
5532    *
5533    * Writing this property sets the #ClutterActor:min-width-set property
5534    * as well, as a side effect.
5535    *
5536    *This property overrides the usual width request of the actor.
5537    *
5538    * Since: 0.8
5539    */
5540   obj_props[PROP_MIN_WIDTH] =
5541     g_param_spec_float ("min-width",
5542                         P_("Min Width"),
5543                         P_("Forced minimum width request for the actor"),
5544                         0.0, G_MAXFLOAT,
5545                         0.0,
5546                         CLUTTER_PARAM_READWRITE);
5547
5548   /**
5549    * ClutterActor:min-height:
5550    *
5551    * A forced minimum height request for the actor, in pixels
5552    *
5553    * Writing this property sets the #ClutterActor:min-height-set property
5554    * as well, as a side effect. This property overrides the usual height
5555    * request of the actor.
5556    *
5557    * Since: 0.8
5558    */
5559   obj_props[PROP_MIN_HEIGHT] =
5560     g_param_spec_float ("min-height",
5561                         P_("Min Height"),
5562                         P_("Forced minimum height request for the actor"),
5563                         0.0, G_MAXFLOAT,
5564                         0.0,
5565                         CLUTTER_PARAM_READWRITE);
5566
5567   /**
5568    * ClutterActor:natural-width:
5569    *
5570    * A forced natural width request for the actor, in pixels
5571    *
5572    * Writing this property sets the #ClutterActor:natural-width-set
5573    * property as well, as a side effect. This property overrides the
5574    * usual width request of the actor
5575    *
5576    * Since: 0.8
5577    */
5578   obj_props[PROP_NATURAL_WIDTH] =
5579     g_param_spec_float ("natural-width",
5580                         P_("Natural Width"),
5581                         P_("Forced natural width request for the actor"),
5582                         0.0, G_MAXFLOAT,
5583                         0.0,
5584                         CLUTTER_PARAM_READWRITE);
5585
5586   /**
5587    * ClutterActor:natural-height:
5588    *
5589    * A forced natural height request for the actor, in pixels
5590    *
5591    * Writing this property sets the #ClutterActor:natural-height-set
5592    * property as well, as a side effect. This property overrides the
5593    * usual height request of the actor
5594    *
5595    * Since: 0.8
5596    */
5597   obj_props[PROP_NATURAL_HEIGHT] =
5598     g_param_spec_float ("natural-height",
5599                         P_("Natural Height"),
5600                         P_("Forced natural height request for the actor"),
5601                         0.0, G_MAXFLOAT,
5602                         0.0,
5603                         CLUTTER_PARAM_READWRITE);
5604
5605   /**
5606    * ClutterActor:min-width-set:
5607    *
5608    * This flag controls whether the #ClutterActor:min-width property
5609    * is used
5610    *
5611    * Since: 0.8
5612    */
5613   obj_props[PROP_MIN_WIDTH_SET] =
5614     g_param_spec_boolean ("min-width-set",
5615                           P_("Minimum width set"),
5616                           P_("Whether to use the min-width property"),
5617                           FALSE,
5618                           CLUTTER_PARAM_READWRITE);
5619
5620   /**
5621    * ClutterActor:min-height-set:
5622    *
5623    * This flag controls whether the #ClutterActor:min-height property
5624    * is used
5625    *
5626    * Since: 0.8
5627    */
5628   obj_props[PROP_MIN_HEIGHT_SET] =
5629     g_param_spec_boolean ("min-height-set",
5630                           P_("Minimum height set"),
5631                           P_("Whether to use the min-height property"),
5632                           FALSE,
5633                           CLUTTER_PARAM_READWRITE);
5634
5635   /**
5636    * ClutterActor:natural-width-set:
5637    *
5638    * This flag controls whether the #ClutterActor:natural-width property
5639    * is used
5640    *
5641    * Since: 0.8
5642    */
5643   obj_props[PROP_NATURAL_WIDTH_SET] =
5644     g_param_spec_boolean ("natural-width-set",
5645                           P_("Natural width set"),
5646                           P_("Whether to use the natural-width property"),
5647                           FALSE,
5648                           CLUTTER_PARAM_READWRITE);
5649
5650   /**
5651    * ClutterActor:natural-height-set:
5652    *
5653    * This flag controls whether the #ClutterActor:natural-height property
5654    * is used
5655    *
5656    * Since: 0.8
5657    */
5658   obj_props[PROP_NATURAL_HEIGHT_SET] =
5659     g_param_spec_boolean ("natural-height-set",
5660                           P_("Natural height set"),
5661                           P_("Whether to use the natural-height property"),
5662                           FALSE,
5663                           CLUTTER_PARAM_READWRITE);
5664
5665   /**
5666    * ClutterActor:allocation:
5667    *
5668    * The allocation for the actor, in pixels
5669    *
5670    * This is property is read-only, but you might monitor it to know when an
5671    * actor moves or resizes
5672    *
5673    * Since: 0.8
5674    */
5675   obj_props[PROP_ALLOCATION] =
5676     g_param_spec_boxed ("allocation",
5677                         P_("Allocation"),
5678                         P_("The actor's allocation"),
5679                         CLUTTER_TYPE_ACTOR_BOX,
5680                         CLUTTER_PARAM_READABLE);
5681
5682   /**
5683    * ClutterActor:request-mode:
5684    *
5685    * Request mode for the #ClutterActor. The request mode determines the
5686    * type of geometry management used by the actor, either height for width
5687    * (the default) or width for height.
5688    *
5689    * For actors implementing height for width, the parent container should get
5690    * the preferred width first, and then the preferred height for that width.
5691    *
5692    * For actors implementing width for height, the parent container should get
5693    * the preferred height first, and then the preferred width for that height.
5694    *
5695    * For instance:
5696    *
5697    * |[
5698    *   ClutterRequestMode mode;
5699    *   gfloat natural_width, min_width;
5700    *   gfloat natural_height, min_height;
5701    *
5702    *   mode = clutter_actor_get_request_mode (child);
5703    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5704    *     {
5705    *       clutter_actor_get_preferred_width (child, -1,
5706    *                                          &amp;min_width,
5707    *                                          &amp;natural_width);
5708    *       clutter_actor_get_preferred_height (child, natural_width,
5709    *                                           &amp;min_height,
5710    *                                           &amp;natural_height);
5711    *     }
5712    *   else
5713    *     {
5714    *       clutter_actor_get_preferred_height (child, -1,
5715    *                                           &amp;min_height,
5716    *                                           &amp;natural_height);
5717    *       clutter_actor_get_preferred_width (child, natural_height,
5718    *                                          &amp;min_width,
5719    *                                          &amp;natural_width);
5720    *     }
5721    * ]|
5722    *
5723    * will retrieve the minimum and natural width and height depending on the
5724    * preferred request mode of the #ClutterActor "child".
5725    *
5726    * The clutter_actor_get_preferred_size() function will implement this
5727    * check for you.
5728    *
5729    * Since: 0.8
5730    */
5731   obj_props[PROP_REQUEST_MODE] =
5732     g_param_spec_enum ("request-mode",
5733                        P_("Request Mode"),
5734                        P_("The actor's request mode"),
5735                        CLUTTER_TYPE_REQUEST_MODE,
5736                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5737                        CLUTTER_PARAM_READWRITE);
5738
5739   /**
5740    * ClutterActor:depth:
5741    *
5742    * The position of the actor on the Z axis.
5743    *
5744    * The #ClutterActor:depth property is relative to the parent's
5745    * modelview matrix.
5746    *
5747    * The #ClutterActor:depth property is animatable.
5748    *
5749    * Since: 0.6
5750    */
5751   obj_props[PROP_DEPTH] =
5752     g_param_spec_float ("depth",
5753                         P_("Depth"),
5754                         P_("Position on the Z axis"),
5755                         -G_MAXFLOAT, G_MAXFLOAT,
5756                         0.0,
5757                         G_PARAM_READWRITE |
5758                         G_PARAM_STATIC_STRINGS |
5759                         CLUTTER_PARAM_ANIMATABLE);
5760
5761   /**
5762    * ClutterActor:opacity:
5763    *
5764    * Opacity of an actor, between 0 (fully transparent) and
5765    * 255 (fully opaque)
5766    *
5767    * The #ClutterActor:opacity property is animatable.
5768    */
5769   obj_props[PROP_OPACITY] =
5770     g_param_spec_uint ("opacity",
5771                        P_("Opacity"),
5772                        P_("Opacity of an actor"),
5773                        0, 255,
5774                        255,
5775                        G_PARAM_READWRITE |
5776                        G_PARAM_STATIC_STRINGS |
5777                        CLUTTER_PARAM_ANIMATABLE);
5778
5779   /**
5780    * ClutterActor:offscreen-redirect:
5781    *
5782    * Determines the conditions in which the actor will be redirected
5783    * to an offscreen framebuffer while being painted. For example this
5784    * can be used to cache an actor in a framebuffer or for improved
5785    * handling of transparent actors. See
5786    * clutter_actor_set_offscreen_redirect() for details.
5787    *
5788    * Since: 1.8
5789    */
5790   obj_props[PROP_OFFSCREEN_REDIRECT] =
5791     g_param_spec_flags ("offscreen-redirect",
5792                         P_("Offscreen redirect"),
5793                         P_("Flags controlling when to flatten the actor into a single image"),
5794                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5795                         0,
5796                         CLUTTER_PARAM_READWRITE);
5797
5798   /**
5799    * ClutterActor:visible:
5800    *
5801    * Whether the actor is set to be visible or not
5802    *
5803    * See also #ClutterActor:mapped
5804    */
5805   obj_props[PROP_VISIBLE] =
5806     g_param_spec_boolean ("visible",
5807                           P_("Visible"),
5808                           P_("Whether the actor is visible or not"),
5809                           FALSE,
5810                           CLUTTER_PARAM_READWRITE);
5811
5812   /**
5813    * ClutterActor:mapped:
5814    *
5815    * Whether the actor is mapped (will be painted when the stage
5816    * to which it belongs is mapped)
5817    *
5818    * Since: 1.0
5819    */
5820   obj_props[PROP_MAPPED] =
5821     g_param_spec_boolean ("mapped",
5822                           P_("Mapped"),
5823                           P_("Whether the actor will be painted"),
5824                           FALSE,
5825                           CLUTTER_PARAM_READABLE);
5826
5827   /**
5828    * ClutterActor:realized:
5829    *
5830    * Whether the actor has been realized
5831    *
5832    * Since: 1.0
5833    */
5834   obj_props[PROP_REALIZED] =
5835     g_param_spec_boolean ("realized",
5836                           P_("Realized"),
5837                           P_("Whether the actor has been realized"),
5838                           FALSE,
5839                           CLUTTER_PARAM_READABLE);
5840
5841   /**
5842    * ClutterActor:reactive:
5843    *
5844    * Whether the actor is reactive to events or not
5845    *
5846    * Only reactive actors will emit event-related signals
5847    *
5848    * Since: 0.6
5849    */
5850   obj_props[PROP_REACTIVE] =
5851     g_param_spec_boolean ("reactive",
5852                           P_("Reactive"),
5853                           P_("Whether the actor is reactive to events"),
5854                           FALSE,
5855                           CLUTTER_PARAM_READWRITE);
5856
5857   /**
5858    * ClutterActor:has-clip:
5859    *
5860    * Whether the actor has the #ClutterActor:clip property set or not
5861    */
5862   obj_props[PROP_HAS_CLIP] =
5863     g_param_spec_boolean ("has-clip",
5864                           P_("Has Clip"),
5865                           P_("Whether the actor has a clip set"),
5866                           FALSE,
5867                           CLUTTER_PARAM_READABLE);
5868
5869   /**
5870    * ClutterActor:clip:
5871    *
5872    * The clip region for the actor, in actor-relative coordinates
5873    *
5874    * Every part of the actor outside the clip region will not be
5875    * painted
5876    */
5877   obj_props[PROP_CLIP] =
5878     g_param_spec_boxed ("clip",
5879                         P_("Clip"),
5880                         P_("The clip region for the actor"),
5881                         CLUTTER_TYPE_GEOMETRY,
5882                         CLUTTER_PARAM_READWRITE);
5883
5884   /**
5885    * ClutterActor:name:
5886    *
5887    * The name of the actor
5888    *
5889    * Since: 0.2
5890    */
5891   obj_props[PROP_NAME] =
5892     g_param_spec_string ("name",
5893                          P_("Name"),
5894                          P_("Name of the actor"),
5895                          NULL,
5896                          CLUTTER_PARAM_READWRITE);
5897
5898   /**
5899    * ClutterActor:scale-x:
5900    *
5901    * The horizontal scale of the actor.
5902    *
5903    * The #ClutterActor:scale-x property is animatable.
5904    *
5905    * Since: 0.6
5906    */
5907   obj_props[PROP_SCALE_X] =
5908     g_param_spec_double ("scale-x",
5909                          P_("Scale X"),
5910                          P_("Scale factor on the X axis"),
5911                          0.0, G_MAXDOUBLE,
5912                          1.0,
5913                          G_PARAM_READWRITE |
5914                          G_PARAM_STATIC_STRINGS |
5915                          CLUTTER_PARAM_ANIMATABLE);
5916
5917   /**
5918    * ClutterActor:scale-y:
5919    *
5920    * The vertical scale of the actor.
5921    *
5922    * The #ClutterActor:scale-y property is animatable.
5923    *
5924    * Since: 0.6
5925    */
5926   obj_props[PROP_SCALE_Y] =
5927     g_param_spec_double ("scale-y",
5928                          P_("Scale Y"),
5929                          P_("Scale factor on the Y axis"),
5930                          0.0, G_MAXDOUBLE,
5931                          1.0,
5932                          G_PARAM_READWRITE |
5933                          G_PARAM_STATIC_STRINGS |
5934                          CLUTTER_PARAM_ANIMATABLE);
5935
5936   /**
5937    * ClutterActor:scale-center-x:
5938    *
5939    * The horizontal center point for scaling
5940    *
5941    * Since: 1.0
5942    */
5943   obj_props[PROP_SCALE_CENTER_X] =
5944     g_param_spec_float ("scale-center-x",
5945                         P_("Scale Center X"),
5946                         P_("Horizontal scale center"),
5947                         -G_MAXFLOAT, G_MAXFLOAT,
5948                         0.0,
5949                         CLUTTER_PARAM_READWRITE);
5950
5951   /**
5952    * ClutterActor:scale-center-y:
5953    *
5954    * The vertical center point for scaling
5955    *
5956    * Since: 1.0
5957    */
5958   obj_props[PROP_SCALE_CENTER_Y] =
5959     g_param_spec_float ("scale-center-y",
5960                         P_("Scale Center Y"),
5961                         P_("Vertical scale center"),
5962                         -G_MAXFLOAT, G_MAXFLOAT,
5963                         0.0,
5964                         CLUTTER_PARAM_READWRITE);
5965
5966   /**
5967    * ClutterActor:scale-gravity:
5968    *
5969    * The center point for scaling expressed as a #ClutterGravity
5970    *
5971    * Since: 1.0
5972    */
5973   obj_props[PROP_SCALE_GRAVITY] =
5974     g_param_spec_enum ("scale-gravity",
5975                        P_("Scale Gravity"),
5976                        P_("The center of scaling"),
5977                        CLUTTER_TYPE_GRAVITY,
5978                        CLUTTER_GRAVITY_NONE,
5979                        CLUTTER_PARAM_READWRITE);
5980
5981   /**
5982    * ClutterActor:rotation-angle-x:
5983    *
5984    * The rotation angle on the X axis.
5985    *
5986    * The #ClutterActor:rotation-angle-x property is animatable.
5987    *
5988    * Since: 0.6
5989    */
5990   obj_props[PROP_ROTATION_ANGLE_X] =
5991     g_param_spec_double ("rotation-angle-x",
5992                          P_("Rotation Angle X"),
5993                          P_("The rotation angle on the X axis"),
5994                          -G_MAXDOUBLE, G_MAXDOUBLE,
5995                          0.0,
5996                          G_PARAM_READWRITE |
5997                          G_PARAM_STATIC_STRINGS |
5998                          CLUTTER_PARAM_ANIMATABLE);
5999
6000   /**
6001    * ClutterActor:rotation-angle-y:
6002    *
6003    * The rotation angle on the Y axis
6004    *
6005    * The #ClutterActor:rotation-angle-y property is animatable.
6006    *
6007    * Since: 0.6
6008    */
6009   obj_props[PROP_ROTATION_ANGLE_Y] =
6010     g_param_spec_double ("rotation-angle-y",
6011                          P_("Rotation Angle Y"),
6012                          P_("The rotation angle on the Y axis"),
6013                          -G_MAXDOUBLE, G_MAXDOUBLE,
6014                          0.0,
6015                          G_PARAM_READWRITE |
6016                          G_PARAM_STATIC_STRINGS |
6017                          CLUTTER_PARAM_ANIMATABLE);
6018
6019   /**
6020    * ClutterActor:rotation-angle-z:
6021    *
6022    * The rotation angle on the Z axis
6023    *
6024    * The #ClutterActor:rotation-angle-z property is animatable.
6025    *
6026    * Since: 0.6
6027    */
6028   obj_props[PROP_ROTATION_ANGLE_Z] =
6029     g_param_spec_double ("rotation-angle-z",
6030                          P_("Rotation Angle Z"),
6031                          P_("The rotation angle on the Z axis"),
6032                          -G_MAXDOUBLE, G_MAXDOUBLE,
6033                          0.0,
6034                          G_PARAM_READWRITE |
6035                          G_PARAM_STATIC_STRINGS |
6036                          CLUTTER_PARAM_ANIMATABLE);
6037
6038   /**
6039    * ClutterActor:rotation-center-x:
6040    *
6041    * The rotation center on the X axis.
6042    *
6043    * Since: 0.6
6044    */
6045   obj_props[PROP_ROTATION_CENTER_X] =
6046     g_param_spec_boxed ("rotation-center-x",
6047                         P_("Rotation Center X"),
6048                         P_("The rotation center on the X axis"),
6049                         CLUTTER_TYPE_VERTEX,
6050                         CLUTTER_PARAM_READWRITE);
6051
6052   /**
6053    * ClutterActor:rotation-center-y:
6054    *
6055    * The rotation center on the Y axis.
6056    *
6057    * Since: 0.6
6058    */
6059   obj_props[PROP_ROTATION_CENTER_Y] =
6060     g_param_spec_boxed ("rotation-center-y",
6061                         P_("Rotation Center Y"),
6062                         P_("The rotation center on the Y axis"),
6063                         CLUTTER_TYPE_VERTEX,
6064                         CLUTTER_PARAM_READWRITE);
6065
6066   /**
6067    * ClutterActor:rotation-center-z:
6068    *
6069    * The rotation center on the Z axis.
6070    *
6071    * Since: 0.6
6072    */
6073   obj_props[PROP_ROTATION_CENTER_Z] =
6074     g_param_spec_boxed ("rotation-center-z",
6075                         P_("Rotation Center Z"),
6076                         P_("The rotation center on the Z axis"),
6077                         CLUTTER_TYPE_VERTEX,
6078                         CLUTTER_PARAM_READWRITE);
6079
6080   /**
6081    * ClutterActor:rotation-center-z-gravity:
6082    *
6083    * The rotation center on the Z axis expressed as a #ClutterGravity.
6084    *
6085    * Since: 1.0
6086    */
6087   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6088     g_param_spec_enum ("rotation-center-z-gravity",
6089                        P_("Rotation Center Z Gravity"),
6090                        P_("Center point for rotation around the Z axis"),
6091                        CLUTTER_TYPE_GRAVITY,
6092                        CLUTTER_GRAVITY_NONE,
6093                        CLUTTER_PARAM_READWRITE);
6094
6095   /**
6096    * ClutterActor:anchor-x:
6097    *
6098    * The X coordinate of an actor's anchor point, relative to
6099    * the actor coordinate space, in pixels
6100    *
6101    * Since: 0.8
6102    */
6103   obj_props[PROP_ANCHOR_X] =
6104     g_param_spec_float ("anchor-x",
6105                         P_("Anchor X"),
6106                         P_("X coordinate of the anchor point"),
6107                         -G_MAXFLOAT, G_MAXFLOAT,
6108                         0,
6109                         CLUTTER_PARAM_READWRITE);
6110
6111   /**
6112    * ClutterActor:anchor-y:
6113    *
6114    * The Y coordinate of an actor's anchor point, relative to
6115    * the actor coordinate space, in pixels
6116    *
6117    * Since: 0.8
6118    */
6119   obj_props[PROP_ANCHOR_Y] =
6120     g_param_spec_float ("anchor-y",
6121                         P_("Anchor Y"),
6122                         P_("Y coordinate of the anchor point"),
6123                         -G_MAXFLOAT, G_MAXFLOAT,
6124                         0,
6125                         CLUTTER_PARAM_READWRITE);
6126
6127   /**
6128    * ClutterActor:anchor-gravity:
6129    *
6130    * The anchor point expressed as a #ClutterGravity
6131    *
6132    * Since: 1.0
6133    */
6134   obj_props[PROP_ANCHOR_GRAVITY] =
6135     g_param_spec_enum ("anchor-gravity",
6136                        P_("Anchor Gravity"),
6137                        P_("The anchor point as a ClutterGravity"),
6138                        CLUTTER_TYPE_GRAVITY,
6139                        CLUTTER_GRAVITY_NONE,
6140                        CLUTTER_PARAM_READWRITE);
6141
6142   /**
6143    * ClutterActor:show-on-set-parent:
6144    *
6145    * If %TRUE, the actor is automatically shown when parented.
6146    *
6147    * Calling clutter_actor_hide() on an actor which has not been
6148    * parented will set this property to %FALSE as a side effect.
6149    *
6150    * Since: 0.8
6151    */
6152   obj_props[PROP_SHOW_ON_SET_PARENT] =
6153     g_param_spec_boolean ("show-on-set-parent",
6154                           P_("Show on set parent"),
6155                           P_("Whether the actor is shown when parented"),
6156                           TRUE,
6157                           CLUTTER_PARAM_READWRITE);
6158
6159   /**
6160    * ClutterActor:clip-to-allocation:
6161    *
6162    * Whether the clip region should track the allocated area
6163    * of the actor.
6164    *
6165    * This property is ignored if a clip area has been explicitly
6166    * set using clutter_actor_set_clip().
6167    *
6168    * Since: 1.0
6169    */
6170   obj_props[PROP_CLIP_TO_ALLOCATION] =
6171     g_param_spec_boolean ("clip-to-allocation",
6172                           P_("Clip to Allocation"),
6173                           P_("Sets the clip region to track the actor's allocation"),
6174                           FALSE,
6175                           CLUTTER_PARAM_READWRITE);
6176
6177   /**
6178    * ClutterActor:text-direction:
6179    *
6180    * The direction of the text inside a #ClutterActor.
6181    *
6182    * Since: 1.0
6183    */
6184   obj_props[PROP_TEXT_DIRECTION] =
6185     g_param_spec_enum ("text-direction",
6186                        P_("Text Direction"),
6187                        P_("Direction of the text"),
6188                        CLUTTER_TYPE_TEXT_DIRECTION,
6189                        CLUTTER_TEXT_DIRECTION_LTR,
6190                        CLUTTER_PARAM_READWRITE);
6191
6192   /**
6193    * ClutterActor:has-pointer:
6194    *
6195    * Whether the actor contains the pointer of a #ClutterInputDevice
6196    * or not.
6197    *
6198    * Since: 1.2
6199    */
6200   obj_props[PROP_HAS_POINTER] =
6201     g_param_spec_boolean ("has-pointer",
6202                           P_("Has Pointer"),
6203                           P_("Whether the actor contains the pointer of an input device"),
6204                           FALSE,
6205                           CLUTTER_PARAM_READABLE);
6206
6207   /**
6208    * ClutterActor:actions:
6209    *
6210    * Adds a #ClutterAction to the actor
6211    *
6212    * Since: 1.4
6213    */
6214   obj_props[PROP_ACTIONS] =
6215     g_param_spec_object ("actions",
6216                          P_("Actions"),
6217                          P_("Adds an action to the actor"),
6218                          CLUTTER_TYPE_ACTION,
6219                          CLUTTER_PARAM_WRITABLE);
6220
6221   /**
6222    * ClutterActor:constraints:
6223    *
6224    * Adds a #ClutterConstraint to the actor
6225    *
6226    * Since: 1.4
6227    */
6228   obj_props[PROP_CONSTRAINTS] =
6229     g_param_spec_object ("constraints",
6230                          P_("Constraints"),
6231                          P_("Adds a constraint to the actor"),
6232                          CLUTTER_TYPE_CONSTRAINT,
6233                          CLUTTER_PARAM_WRITABLE);
6234
6235   /**
6236    * ClutterActor:effect:
6237    *
6238    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6239    *
6240    * Since: 1.4
6241    */
6242   obj_props[PROP_EFFECT] =
6243     g_param_spec_object ("effect",
6244                          P_("Effect"),
6245                          P_("Add an effect to be applied on the actor"),
6246                          CLUTTER_TYPE_EFFECT,
6247                          CLUTTER_PARAM_WRITABLE);
6248
6249   /**
6250    * ClutterActor:layout-manager:
6251    *
6252    * A delegate object for controlling the layout of the children of
6253    * an actor.
6254    *
6255    * Since: 1.10
6256    */
6257   obj_props[PROP_LAYOUT_MANAGER] =
6258     g_param_spec_object ("layout-manager",
6259                          P_("Layout Manager"),
6260                          P_("The object controlling the layout of an actor's children"),
6261                          CLUTTER_TYPE_LAYOUT_MANAGER,
6262                          CLUTTER_PARAM_READWRITE);
6263
6264
6265   /**
6266    * ClutterActor:x-align:
6267    *
6268    * The alignment of an actor on the X axis, if the actor has been given
6269    * extra space for its allocation.
6270    *
6271    * Since: 1.10
6272    */
6273   obj_props[PROP_X_ALIGN] =
6274     g_param_spec_enum ("x-align",
6275                        P_("X Alignment"),
6276                        P_("The alignment of the actor on the X axis within its allocation"),
6277                        CLUTTER_TYPE_ACTOR_ALIGN,
6278                        CLUTTER_ACTOR_ALIGN_FILL,
6279                        CLUTTER_PARAM_READWRITE);
6280
6281   /**
6282    * ClutterActor:y-align:
6283    *
6284    * The alignment of an actor on the Y axis, if the actor has been given
6285    * extra space for its allocation.
6286    *
6287    * Since: 1.10
6288    */
6289   obj_props[PROP_Y_ALIGN] =
6290     g_param_spec_enum ("y-align",
6291                        P_("Y Alignment"),
6292                        P_("The alignment of the actor on the Y axis within its allocation"),
6293                        CLUTTER_TYPE_ACTOR_ALIGN,
6294                        CLUTTER_ACTOR_ALIGN_FILL,
6295                        CLUTTER_PARAM_READWRITE);
6296
6297   /**
6298    * ClutterActor:margin-top:
6299    *
6300    * The margin (in pixels) from the top of the actor.
6301    *
6302    * This property adds a margin to the actor's preferred size; the margin
6303    * will be automatically taken into account when allocating the actor.
6304    *
6305    * Since: 1.10
6306    */
6307   obj_props[PROP_MARGIN_TOP] =
6308     g_param_spec_float ("margin-top",
6309                         P_("Margin Top"),
6310                         P_("Extra space at the top"),
6311                         0.0, G_MAXFLOAT,
6312                         0.0,
6313                         CLUTTER_PARAM_READWRITE);
6314
6315   /**
6316    * ClutterActor:margin-bottom:
6317    *
6318    * The margin (in pixels) from the bottom of the actor.
6319    *
6320    * This property adds a margin to the actor's preferred size; the margin
6321    * will be automatically taken into account when allocating the actor.
6322    *
6323    * Since: 1.10
6324    */
6325   obj_props[PROP_MARGIN_BOTTOM] =
6326     g_param_spec_float ("margin-bottom",
6327                         P_("Margin Bottom"),
6328                         P_("Extra space at the bottom"),
6329                         0.0, G_MAXFLOAT,
6330                         0.0,
6331                         CLUTTER_PARAM_READWRITE);
6332
6333   /**
6334    * ClutterActor:margin-left:
6335    *
6336    * The margin (in pixels) from the left of the actor.
6337    *
6338    * This property adds a margin to the actor's preferred size; the margin
6339    * will be automatically taken into account when allocating the actor.
6340    *
6341    * Since: 1.10
6342    */
6343   obj_props[PROP_MARGIN_LEFT] =
6344     g_param_spec_float ("margin-left",
6345                         P_("Margin Left"),
6346                         P_("Extra space at the left"),
6347                         0.0, G_MAXFLOAT,
6348                         0.0,
6349                         CLUTTER_PARAM_READWRITE);
6350
6351   /**
6352    * ClutterActor:margin-right:
6353    *
6354    * The margin (in pixels) from the right of the actor.
6355    *
6356    * This property adds a margin to the actor's preferred size; the margin
6357    * will be automatically taken into account when allocating the actor.
6358    *
6359    * Since: 1.10
6360    */
6361   obj_props[PROP_MARGIN_RIGHT] =
6362     g_param_spec_float ("margin-right",
6363                         P_("Margin Right"),
6364                         P_("Extra space at the right"),
6365                         0.0, G_MAXFLOAT,
6366                         0.0,
6367                         CLUTTER_PARAM_READWRITE);
6368
6369   /**
6370    * ClutterActor:background-color-set:
6371    *
6372    * Whether the #ClutterActor:background-color property has been set.
6373    *
6374    * Since: 1.10
6375    */
6376   obj_props[PROP_BACKGROUND_COLOR_SET] =
6377     g_param_spec_boolean ("background-color-set",
6378                           P_("Background Color Set"),
6379                           P_("Whether the background color is set"),
6380                           FALSE,
6381                           CLUTTER_PARAM_READABLE);
6382
6383   /**
6384    * ClutterActor:background-color:
6385    *
6386    * Paints a solid fill of the actor's allocation using the specified
6387    * color.
6388    *
6389    * The #ClutterActor:background-color property is animatable.
6390    *
6391    * Since: 1.10
6392    */
6393   obj_props[PROP_BACKGROUND_COLOR] =
6394     clutter_param_spec_color ("background-color",
6395                               P_("Background color"),
6396                               P_("The actor's background color"),
6397                               CLUTTER_COLOR_Transparent,
6398                               G_PARAM_READWRITE |
6399                               G_PARAM_STATIC_STRINGS |
6400                               CLUTTER_PARAM_ANIMATABLE);
6401
6402   /**
6403    * ClutterActor:first-child:
6404    *
6405    * The actor's first child.
6406    *
6407    * Since: 1.10
6408    */
6409   obj_props[PROP_FIRST_CHILD] =
6410     g_param_spec_object ("first-child",
6411                          P_("First Child"),
6412                          P_("The actor's first child"),
6413                          CLUTTER_TYPE_ACTOR,
6414                          CLUTTER_PARAM_READABLE);
6415
6416   /**
6417    * ClutterActor:last-child:
6418    *
6419    * The actor's last child.
6420    *
6421    * Since: 1.10
6422    */
6423   obj_props[PROP_LAST_CHILD] =
6424     g_param_spec_object ("last-child",
6425                          P_("Last Child"),
6426                          P_("The actor's last child"),
6427                          CLUTTER_TYPE_ACTOR,
6428                          CLUTTER_PARAM_READABLE);
6429
6430   /**
6431    * ClutterActor:content:
6432    *
6433    * The #ClutterContent implementation that controls the content
6434    * of the actor.
6435    *
6436    * Since: 1.10
6437    */
6438   obj_props[PROP_CONTENT] =
6439     g_param_spec_object ("content",
6440                          P_("Content"),
6441                          P_("Delegate object for painting the actor's content"),
6442                          CLUTTER_TYPE_CONTENT,
6443                          CLUTTER_PARAM_READWRITE);
6444
6445   /**
6446    * ClutterActor:content-gravity:
6447    *
6448    * The alignment that should be honoured by the #ClutterContent
6449    * set with the #ClutterActor:content property.
6450    *
6451    * Changing the value of this property will change the bounding box of
6452    * the content; you can use the #ClutterActor:content-box property to
6453    * get the position and size of the content within the actor's
6454    * allocation.
6455    *
6456    * This property is meaningful only for #ClutterContent implementations
6457    * that have a preferred size, and if the preferred size is smaller than
6458    * the actor's allocation.
6459    *
6460    * The #ClutterActor:content-gravity property is animatable.
6461    *
6462    * Since: 1.10
6463    */
6464   obj_props[PROP_CONTENT_GRAVITY] =
6465     g_param_spec_enum ("content-gravity",
6466                        P_("Content Gravity"),
6467                        P_("Alignment of the actor's content"),
6468                        CLUTTER_TYPE_CONTENT_GRAVITY,
6469                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6470                        CLUTTER_PARAM_READWRITE);
6471
6472   /**
6473    * ClutterActor:content-box:
6474    *
6475    * The bounding box for the #ClutterContent used by the actor.
6476    *
6477    * The value of this property is controlled by the #ClutterActor:allocation
6478    * and #ClutterActor:content-gravity properties of #ClutterActor.
6479    *
6480    * The bounding box for the content is guaranteed to never exceed the
6481    * allocation's of the actor.
6482    *
6483    * Since: 1.10
6484    */
6485   obj_props[PROP_CONTENT_BOX] =
6486     g_param_spec_boxed ("content-box",
6487                         P_("Content Box"),
6488                         P_("The bounding box of the actor's content"),
6489                         CLUTTER_TYPE_ACTOR_BOX,
6490                         G_PARAM_READABLE |
6491                         G_PARAM_STATIC_STRINGS |
6492                         CLUTTER_PARAM_ANIMATABLE);
6493
6494   obj_props[PROP_MINIFICATION_FILTER] =
6495     g_param_spec_enum ("minification-filter",
6496                        P_("Minification Filter"),
6497                        P_("The filter used when reducing the size of the content"),
6498                        CLUTTER_TYPE_SCALING_FILTER,
6499                        CLUTTER_SCALING_FILTER_LINEAR,
6500                        CLUTTER_PARAM_READWRITE);
6501
6502   obj_props[PROP_MAGNIFICATION_FILTER] =
6503     g_param_spec_enum ("magnification-filter",
6504                        P_("Magnification Filter"),
6505                        P_("The filter used when increasing the size of the content"),
6506                        CLUTTER_TYPE_SCALING_FILTER,
6507                        CLUTTER_SCALING_FILTER_LINEAR,
6508                        CLUTTER_PARAM_READWRITE);
6509
6510   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6511
6512   /**
6513    * ClutterActor::destroy:
6514    * @actor: the #ClutterActor which emitted the signal
6515    *
6516    * The ::destroy signal notifies that all references held on the
6517    * actor which emitted it should be released.
6518    *
6519    * The ::destroy signal should be used by all holders of a reference
6520    * on @actor.
6521    *
6522    * This signal might result in the finalization of the #ClutterActor
6523    * if all references are released.
6524    *
6525    * Composite actors and actors implementing the #ClutterContainer
6526    * interface should override the default implementation of the
6527    * class handler of this signal and call clutter_actor_destroy() on
6528    * their children. When overriding the default class handler, it is
6529    * required to chain up to the parent's implementation.
6530    *
6531    * Since: 0.2
6532    */
6533   actor_signals[DESTROY] =
6534     g_signal_new (I_("destroy"),
6535                   G_TYPE_FROM_CLASS (object_class),
6536                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6537                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6538                   NULL, NULL,
6539                   _clutter_marshal_VOID__VOID,
6540                   G_TYPE_NONE, 0);
6541   /**
6542    * ClutterActor::show:
6543    * @actor: the object which received the signal
6544    *
6545    * The ::show signal is emitted when an actor is visible and
6546    * rendered on the stage.
6547    *
6548    * Since: 0.2
6549    */
6550   actor_signals[SHOW] =
6551     g_signal_new (I_("show"),
6552                   G_TYPE_FROM_CLASS (object_class),
6553                   G_SIGNAL_RUN_FIRST,
6554                   G_STRUCT_OFFSET (ClutterActorClass, show),
6555                   NULL, NULL,
6556                   _clutter_marshal_VOID__VOID,
6557                   G_TYPE_NONE, 0);
6558   /**
6559    * ClutterActor::hide:
6560    * @actor: the object which received the signal
6561    *
6562    * The ::hide signal is emitted when an actor is no longer rendered
6563    * on the stage.
6564    *
6565    * Since: 0.2
6566    */
6567   actor_signals[HIDE] =
6568     g_signal_new (I_("hide"),
6569                   G_TYPE_FROM_CLASS (object_class),
6570                   G_SIGNAL_RUN_FIRST,
6571                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6572                   NULL, NULL,
6573                   _clutter_marshal_VOID__VOID,
6574                   G_TYPE_NONE, 0);
6575   /**
6576    * ClutterActor::parent-set:
6577    * @actor: the object which received the signal
6578    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6579    *
6580    * This signal is emitted when the parent of the actor changes.
6581    *
6582    * Since: 0.2
6583    */
6584   actor_signals[PARENT_SET] =
6585     g_signal_new (I_("parent-set"),
6586                   G_TYPE_FROM_CLASS (object_class),
6587                   G_SIGNAL_RUN_LAST,
6588                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6589                   NULL, NULL,
6590                   _clutter_marshal_VOID__OBJECT,
6591                   G_TYPE_NONE, 1,
6592                   CLUTTER_TYPE_ACTOR);
6593
6594   /**
6595    * ClutterActor::queue-redraw:
6596    * @actor: the actor we're bubbling the redraw request through
6597    * @origin: the actor which initiated the redraw request
6598    *
6599    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6600    * is called on @origin.
6601    *
6602    * The default implementation for #ClutterActor chains up to the
6603    * parent actor and queues a redraw on the parent, thus "bubbling"
6604    * the redraw queue up through the actor graph. The default
6605    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6606    * in a main loop idle handler.
6607    *
6608    * Note that the @origin actor may be the stage, or a container; it
6609    * does not have to be a leaf node in the actor graph.
6610    *
6611    * Toolkits embedding a #ClutterStage which require a redraw and
6612    * relayout cycle can stop the emission of this signal using the
6613    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6614    * themselves, like:
6615    *
6616    * |[
6617    *   static void
6618    *   on_redraw_complete (gpointer data)
6619    *   {
6620    *     ClutterStage *stage = data;
6621    *
6622    *     /&ast; execute the Clutter drawing pipeline &ast;/
6623    *     clutter_stage_ensure_redraw (stage);
6624    *   }
6625    *
6626    *   static void
6627    *   on_stage_queue_redraw (ClutterStage *stage)
6628    *   {
6629    *     /&ast; this prevents the default handler to run &ast;/
6630    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6631    *
6632    *     /&ast; queue a redraw with the host toolkit and call
6633    *      &ast; a function when the redraw has been completed
6634    *      &ast;/
6635    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6636    *   }
6637    * ]|
6638    *
6639    * <note><para>This signal is emitted before the Clutter paint
6640    * pipeline is executed. If you want to know when the pipeline has
6641    * been completed you should connect to the ::paint signal on the
6642    * Stage with g_signal_connect_after().</para></note>
6643    *
6644    * Since: 1.0
6645    */
6646   actor_signals[QUEUE_REDRAW] =
6647     g_signal_new (I_("queue-redraw"),
6648                   G_TYPE_FROM_CLASS (object_class),
6649                   G_SIGNAL_RUN_LAST |
6650                   G_SIGNAL_NO_HOOKS,
6651                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6652                   NULL, NULL,
6653                   _clutter_marshal_VOID__OBJECT,
6654                   G_TYPE_NONE, 1,
6655                   CLUTTER_TYPE_ACTOR);
6656
6657   /**
6658    * ClutterActor::queue-relayout
6659    * @actor: the actor being queued for relayout
6660    *
6661    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6662    * is called on an actor.
6663    *
6664    * The default implementation for #ClutterActor chains up to the
6665    * parent actor and queues a relayout on the parent, thus "bubbling"
6666    * the relayout queue up through the actor graph.
6667    *
6668    * The main purpose of this signal is to allow relayout to be propagated
6669    * properly in the procense of #ClutterClone actors. Applications will
6670    * not normally need to connect to this signal.
6671    *
6672    * Since: 1.2
6673    */
6674   actor_signals[QUEUE_RELAYOUT] =
6675     g_signal_new (I_("queue-relayout"),
6676                   G_TYPE_FROM_CLASS (object_class),
6677                   G_SIGNAL_RUN_LAST |
6678                   G_SIGNAL_NO_HOOKS,
6679                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6680                   NULL, NULL,
6681                   _clutter_marshal_VOID__VOID,
6682                   G_TYPE_NONE, 0);
6683
6684   /**
6685    * ClutterActor::event:
6686    * @actor: the actor which received the event
6687    * @event: a #ClutterEvent
6688    *
6689    * The ::event signal is emitted each time an event is received
6690    * by the @actor. This signal will be emitted on every actor,
6691    * following the hierarchy chain, until it reaches the top-level
6692    * container (the #ClutterStage).
6693    *
6694    * Return value: %TRUE if the event has been handled by the actor,
6695    *   or %FALSE to continue the emission.
6696    *
6697    * Since: 0.6
6698    */
6699   actor_signals[EVENT] =
6700     g_signal_new (I_("event"),
6701                   G_TYPE_FROM_CLASS (object_class),
6702                   G_SIGNAL_RUN_LAST,
6703                   G_STRUCT_OFFSET (ClutterActorClass, event),
6704                   _clutter_boolean_handled_accumulator, NULL,
6705                   _clutter_marshal_BOOLEAN__BOXED,
6706                   G_TYPE_BOOLEAN, 1,
6707                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6708   /**
6709    * ClutterActor::button-press-event:
6710    * @actor: the actor which received the event
6711    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6712    *
6713    * The ::button-press-event signal is emitted each time a mouse button
6714    * is pressed on @actor.
6715    *
6716    * Return value: %TRUE if the event has been handled by the actor,
6717    *   or %FALSE to continue the emission.
6718    *
6719    * Since: 0.6
6720    */
6721   actor_signals[BUTTON_PRESS_EVENT] =
6722     g_signal_new (I_("button-press-event"),
6723                   G_TYPE_FROM_CLASS (object_class),
6724                   G_SIGNAL_RUN_LAST,
6725                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6726                   _clutter_boolean_handled_accumulator, NULL,
6727                   _clutter_marshal_BOOLEAN__BOXED,
6728                   G_TYPE_BOOLEAN, 1,
6729                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6730   /**
6731    * ClutterActor::button-release-event:
6732    * @actor: the actor which received the event
6733    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6734    *
6735    * The ::button-release-event signal is emitted each time a mouse button
6736    * is released on @actor.
6737    *
6738    * Return value: %TRUE if the event has been handled by the actor,
6739    *   or %FALSE to continue the emission.
6740    *
6741    * Since: 0.6
6742    */
6743   actor_signals[BUTTON_RELEASE_EVENT] =
6744     g_signal_new (I_("button-release-event"),
6745                   G_TYPE_FROM_CLASS (object_class),
6746                   G_SIGNAL_RUN_LAST,
6747                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6748                   _clutter_boolean_handled_accumulator, NULL,
6749                   _clutter_marshal_BOOLEAN__BOXED,
6750                   G_TYPE_BOOLEAN, 1,
6751                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6752   /**
6753    * ClutterActor::scroll-event:
6754    * @actor: the actor which received the event
6755    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6756    *
6757    * The ::scroll-event signal is emitted each time the mouse is
6758    * scrolled on @actor
6759    *
6760    * Return value: %TRUE if the event has been handled by the actor,
6761    *   or %FALSE to continue the emission.
6762    *
6763    * Since: 0.6
6764    */
6765   actor_signals[SCROLL_EVENT] =
6766     g_signal_new (I_("scroll-event"),
6767                   G_TYPE_FROM_CLASS (object_class),
6768                   G_SIGNAL_RUN_LAST,
6769                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6770                   _clutter_boolean_handled_accumulator, NULL,
6771                   _clutter_marshal_BOOLEAN__BOXED,
6772                   G_TYPE_BOOLEAN, 1,
6773                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6774   /**
6775    * ClutterActor::key-press-event:
6776    * @actor: the actor which received the event
6777    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6778    *
6779    * The ::key-press-event signal is emitted each time a keyboard button
6780    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6781    *
6782    * Return value: %TRUE if the event has been handled by the actor,
6783    *   or %FALSE to continue the emission.
6784    *
6785    * Since: 0.6
6786    */
6787   actor_signals[KEY_PRESS_EVENT] =
6788     g_signal_new (I_("key-press-event"),
6789                   G_TYPE_FROM_CLASS (object_class),
6790                   G_SIGNAL_RUN_LAST,
6791                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6792                   _clutter_boolean_handled_accumulator, NULL,
6793                   _clutter_marshal_BOOLEAN__BOXED,
6794                   G_TYPE_BOOLEAN, 1,
6795                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6796   /**
6797    * ClutterActor::key-release-event:
6798    * @actor: the actor which received the event
6799    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6800    *
6801    * The ::key-release-event signal is emitted each time a keyboard button
6802    * is released while @actor has key focus (see
6803    * clutter_stage_set_key_focus()).
6804    *
6805    * Return value: %TRUE if the event has been handled by the actor,
6806    *   or %FALSE to continue the emission.
6807    *
6808    * Since: 0.6
6809    */
6810   actor_signals[KEY_RELEASE_EVENT] =
6811     g_signal_new (I_("key-release-event"),
6812                   G_TYPE_FROM_CLASS (object_class),
6813                   G_SIGNAL_RUN_LAST,
6814                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6815                   _clutter_boolean_handled_accumulator, NULL,
6816                   _clutter_marshal_BOOLEAN__BOXED,
6817                   G_TYPE_BOOLEAN, 1,
6818                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6819   /**
6820    * ClutterActor::motion-event:
6821    * @actor: the actor which received the event
6822    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6823    *
6824    * The ::motion-event signal is emitted each time the mouse pointer is
6825    * moved over @actor.
6826    *
6827    * Return value: %TRUE if the event has been handled by the actor,
6828    *   or %FALSE to continue the emission.
6829    *
6830    * Since: 0.6
6831    */
6832   actor_signals[MOTION_EVENT] =
6833     g_signal_new (I_("motion-event"),
6834                   G_TYPE_FROM_CLASS (object_class),
6835                   G_SIGNAL_RUN_LAST,
6836                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6837                   _clutter_boolean_handled_accumulator, NULL,
6838                   _clutter_marshal_BOOLEAN__BOXED,
6839                   G_TYPE_BOOLEAN, 1,
6840                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6841
6842   /**
6843    * ClutterActor::key-focus-in:
6844    * @actor: the actor which now has key focus
6845    *
6846    * The ::key-focus-in signal is emitted when @actor receives key focus.
6847    *
6848    * Since: 0.6
6849    */
6850   actor_signals[KEY_FOCUS_IN] =
6851     g_signal_new (I_("key-focus-in"),
6852                   G_TYPE_FROM_CLASS (object_class),
6853                   G_SIGNAL_RUN_LAST,
6854                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6855                   NULL, NULL,
6856                   _clutter_marshal_VOID__VOID,
6857                   G_TYPE_NONE, 0);
6858
6859   /**
6860    * ClutterActor::key-focus-out:
6861    * @actor: the actor which now has key focus
6862    *
6863    * The ::key-focus-out signal is emitted when @actor loses key focus.
6864    *
6865    * Since: 0.6
6866    */
6867   actor_signals[KEY_FOCUS_OUT] =
6868     g_signal_new (I_("key-focus-out"),
6869                   G_TYPE_FROM_CLASS (object_class),
6870                   G_SIGNAL_RUN_LAST,
6871                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6872                   NULL, NULL,
6873                   _clutter_marshal_VOID__VOID,
6874                   G_TYPE_NONE, 0);
6875
6876   /**
6877    * ClutterActor::enter-event:
6878    * @actor: the actor which the pointer has entered.
6879    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6880    *
6881    * The ::enter-event signal is emitted when the pointer enters the @actor
6882    *
6883    * Return value: %TRUE if the event has been handled by the actor,
6884    *   or %FALSE to continue the emission.
6885    *
6886    * Since: 0.6
6887    */
6888   actor_signals[ENTER_EVENT] =
6889     g_signal_new (I_("enter-event"),
6890                   G_TYPE_FROM_CLASS (object_class),
6891                   G_SIGNAL_RUN_LAST,
6892                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6893                   _clutter_boolean_handled_accumulator, NULL,
6894                   _clutter_marshal_BOOLEAN__BOXED,
6895                   G_TYPE_BOOLEAN, 1,
6896                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6897
6898   /**
6899    * ClutterActor::leave-event:
6900    * @actor: the actor which the pointer has left
6901    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6902    *
6903    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6904    *
6905    * Return value: %TRUE if the event has been handled by the actor,
6906    *   or %FALSE to continue the emission.
6907    *
6908    * Since: 0.6
6909    */
6910   actor_signals[LEAVE_EVENT] =
6911     g_signal_new (I_("leave-event"),
6912                   G_TYPE_FROM_CLASS (object_class),
6913                   G_SIGNAL_RUN_LAST,
6914                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6915                   _clutter_boolean_handled_accumulator, NULL,
6916                   _clutter_marshal_BOOLEAN__BOXED,
6917                   G_TYPE_BOOLEAN, 1,
6918                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6919
6920   /**
6921    * ClutterActor::captured-event:
6922    * @actor: the actor which received the signal
6923    * @event: a #ClutterEvent
6924    *
6925    * The ::captured-event signal is emitted when an event is captured
6926    * by Clutter. This signal will be emitted starting from the top-level
6927    * container (the #ClutterStage) to the actor which received the event
6928    * going down the hierarchy. This signal can be used to intercept every
6929    * event before the specialized events (like
6930    * ClutterActor::button-press-event or ::key-released-event) are
6931    * emitted.
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[CAPTURED_EVENT] =
6939     g_signal_new (I_("captured-event"),
6940                   G_TYPE_FROM_CLASS (object_class),
6941                   G_SIGNAL_RUN_LAST,
6942                   G_STRUCT_OFFSET (ClutterActorClass, captured_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::paint:
6950    * @actor: the #ClutterActor that received the signal
6951    *
6952    * The ::paint signal is emitted each time an actor is being painted.
6953    *
6954    * Subclasses of #ClutterActor should override the class signal handler
6955    * and paint themselves in that function.
6956    *
6957    * It is possible to connect a handler to the ::paint signal in order
6958    * to set up some custom aspect of a paint.
6959    *
6960    * Since: 0.8
6961    */
6962   actor_signals[PAINT] =
6963     g_signal_new (I_("paint"),
6964                   G_TYPE_FROM_CLASS (object_class),
6965                   G_SIGNAL_RUN_LAST |
6966                   G_SIGNAL_NO_HOOKS,
6967                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6968                   NULL, NULL,
6969                   _clutter_marshal_VOID__VOID,
6970                   G_TYPE_NONE, 0);
6971   /**
6972    * ClutterActor::realize:
6973    * @actor: the #ClutterActor that received the signal
6974    *
6975    * The ::realize signal is emitted each time an actor is being
6976    * realized.
6977    *
6978    * Since: 0.8
6979    */
6980   actor_signals[REALIZE] =
6981     g_signal_new (I_("realize"),
6982                   G_TYPE_FROM_CLASS (object_class),
6983                   G_SIGNAL_RUN_LAST,
6984                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6985                   NULL, NULL,
6986                   _clutter_marshal_VOID__VOID,
6987                   G_TYPE_NONE, 0);
6988   /**
6989    * ClutterActor::unrealize:
6990    * @actor: the #ClutterActor that received the signal
6991    *
6992    * The ::unrealize signal is emitted each time an actor is being
6993    * unrealized.
6994    *
6995    * Since: 0.8
6996    */
6997   actor_signals[UNREALIZE] =
6998     g_signal_new (I_("unrealize"),
6999                   G_TYPE_FROM_CLASS (object_class),
7000                   G_SIGNAL_RUN_LAST,
7001                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7002                   NULL, NULL,
7003                   _clutter_marshal_VOID__VOID,
7004                   G_TYPE_NONE, 0);
7005
7006   /**
7007    * ClutterActor::pick:
7008    * @actor: the #ClutterActor that received the signal
7009    * @color: the #ClutterColor to be used when picking
7010    *
7011    * The ::pick signal is emitted each time an actor is being painted
7012    * in "pick mode". The pick mode is used to identify the actor during
7013    * the event handling phase, or by clutter_stage_get_actor_at_pos().
7014    * The actor should paint its shape using the passed @pick_color.
7015    *
7016    * Subclasses of #ClutterActor should override the class signal handler
7017    * and paint themselves in that function.
7018    *
7019    * It is possible to connect a handler to the ::pick signal in order
7020    * to set up some custom aspect of a paint in pick mode.
7021    *
7022    * Since: 1.0
7023    */
7024   actor_signals[PICK] =
7025     g_signal_new (I_("pick"),
7026                   G_TYPE_FROM_CLASS (object_class),
7027                   G_SIGNAL_RUN_LAST,
7028                   G_STRUCT_OFFSET (ClutterActorClass, pick),
7029                   NULL, NULL,
7030                   _clutter_marshal_VOID__BOXED,
7031                   G_TYPE_NONE, 1,
7032                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7033
7034   /**
7035    * ClutterActor::allocation-changed:
7036    * @actor: the #ClutterActor that emitted the signal
7037    * @box: a #ClutterActorBox with the new allocation
7038    * @flags: #ClutterAllocationFlags for the allocation
7039    *
7040    * The ::allocation-changed signal is emitted when the
7041    * #ClutterActor:allocation property changes. Usually, application
7042    * code should just use the notifications for the :allocation property
7043    * but if you want to track the allocation flags as well, for instance
7044    * to know whether the absolute origin of @actor changed, then you might
7045    * want use this signal instead.
7046    *
7047    * Since: 1.0
7048    */
7049   actor_signals[ALLOCATION_CHANGED] =
7050     g_signal_new (I_("allocation-changed"),
7051                   G_TYPE_FROM_CLASS (object_class),
7052                   G_SIGNAL_RUN_LAST,
7053                   0,
7054                   NULL, NULL,
7055                   _clutter_marshal_VOID__BOXED_FLAGS,
7056                   G_TYPE_NONE, 2,
7057                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7058                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7059
7060   /**
7061    * ClutterActor::transitions-completed:
7062    * @actor: a #ClutterActor
7063    *
7064    * The ::transitions-completed signal is emitted once all transitions
7065    * involving @actor are complete.
7066    *
7067    * Since: 1.10
7068    */
7069   actor_signals[TRANSITIONS_COMPLETED] =
7070     g_signal_new (I_("transitions-completed"),
7071                   G_TYPE_FROM_CLASS (object_class),
7072                   G_SIGNAL_RUN_LAST,
7073                   0,
7074                   NULL, NULL,
7075                   _clutter_marshal_VOID__VOID,
7076                   G_TYPE_NONE, 0);
7077 }
7078
7079 static void
7080 clutter_actor_init (ClutterActor *self)
7081 {
7082   ClutterActorPrivate *priv;
7083
7084   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7085
7086   priv->id = _clutter_context_acquire_id (self);
7087   priv->pick_id = -1;
7088
7089   priv->opacity = 0xff;
7090   priv->show_on_set_parent = TRUE;
7091
7092   priv->needs_width_request = TRUE;
7093   priv->needs_height_request = TRUE;
7094   priv->needs_allocation = TRUE;
7095
7096   priv->cached_width_age = 1;
7097   priv->cached_height_age = 1;
7098
7099   priv->opacity_override = -1;
7100   priv->enable_model_view_transform = TRUE;
7101
7102   /* Initialize an empty paint volume to start with */
7103   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7104   priv->last_paint_volume_valid = TRUE;
7105
7106   priv->transform_valid = FALSE;
7107
7108   /* the default is to stretch the content, to match the
7109    * current behaviour of basically all actors. also, it's
7110    * the easiest thing to compute.
7111    */
7112   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7113   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7114   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7115 }
7116
7117 /**
7118  * clutter_actor_new:
7119  *
7120  * Creates a new #ClutterActor.
7121  *
7122  * A newly created actor has a floating reference, which will be sunk
7123  * when it is added to another actor.
7124  *
7125  * Return value: (transfer full): the newly created #ClutterActor
7126  *
7127  * Since: 1.10
7128  */
7129 ClutterActor *
7130 clutter_actor_new (void)
7131 {
7132   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7133 }
7134
7135 /**
7136  * clutter_actor_destroy:
7137  * @self: a #ClutterActor
7138  *
7139  * Destroys an actor.  When an actor is destroyed, it will break any
7140  * references it holds to other objects.  If the actor is inside a
7141  * container, the actor will be removed.
7142  *
7143  * When you destroy a container, its children will be destroyed as well.
7144  *
7145  * Note: you cannot destroy the #ClutterStage returned by
7146  * clutter_stage_get_default().
7147  */
7148 void
7149 clutter_actor_destroy (ClutterActor *self)
7150 {
7151   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7152
7153   g_object_ref (self);
7154
7155   /* avoid recursion while destroying */
7156   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7157     {
7158       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7159
7160       g_object_run_dispose (G_OBJECT (self));
7161
7162       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7163     }
7164
7165   g_object_unref (self);
7166 }
7167
7168 void
7169 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7170                                     ClutterPaintVolume *clip)
7171 {
7172   ClutterActorPrivate *priv = self->priv;
7173   ClutterPaintVolume *pv;
7174   gboolean clipped;
7175
7176   /* Remove queue entry early in the process, otherwise a new
7177      queue_redraw() during signal handling could put back this
7178      object in the stage redraw list (but the entry is freed as
7179      soon as we return from this function, causing a segfault
7180      later)
7181   */
7182   priv->queue_redraw_entry = NULL;
7183
7184   /* If we've been explicitly passed a clip volume then there's
7185    * nothing more to calculate, but otherwise the only thing we know
7186    * is that the change is constrained to the given actor.
7187    *
7188    * The idea is that if we know the paint volume for where the actor
7189    * was last drawn (in eye coordinates) and we also have the paint
7190    * volume for where it will be drawn next (in actor coordinates)
7191    * then if we queue a redraw for both these volumes that will cover
7192    * everything that needs to be redrawn to clear the old view and
7193    * show the latest view of the actor.
7194    *
7195    * Don't clip this redraw if we don't know what position we had for
7196    * the previous redraw since we don't know where to set the clip so
7197    * it will clear the actor as it is currently.
7198    */
7199   if (clip)
7200     {
7201       _clutter_actor_set_queue_redraw_clip (self, clip);
7202       clipped = TRUE;
7203     }
7204   else if (G_LIKELY (priv->last_paint_volume_valid))
7205     {
7206       pv = _clutter_actor_get_paint_volume_mutable (self);
7207       if (pv)
7208         {
7209           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7210
7211           /* make sure we redraw the actors old position... */
7212           _clutter_actor_set_queue_redraw_clip (stage,
7213                                                 &priv->last_paint_volume);
7214           _clutter_actor_signal_queue_redraw (stage, stage);
7215           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7216
7217           /* XXX: Ideally the redraw signal would take a clip volume
7218            * argument, but that would be an ABI break. Until we can
7219            * break the ABI we pass the argument out-of-band
7220            */
7221
7222           /* setup the clip for the actors new position... */
7223           _clutter_actor_set_queue_redraw_clip (self, pv);
7224           clipped = TRUE;
7225         }
7226       else
7227         clipped = FALSE;
7228     }
7229   else
7230     clipped = FALSE;
7231
7232   _clutter_actor_signal_queue_redraw (self, self);
7233
7234   /* Just in case anyone is manually firing redraw signals without
7235    * using the public queue_redraw() API we are careful to ensure that
7236    * our out-of-band clip member is cleared before returning...
7237    *
7238    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7239    */
7240   if (G_LIKELY (clipped))
7241     _clutter_actor_set_queue_redraw_clip (self, NULL);
7242 }
7243
7244 static void
7245 _clutter_actor_get_allocation_clip (ClutterActor *self,
7246                                     ClutterActorBox *clip)
7247 {
7248   ClutterActorBox allocation;
7249
7250   /* XXX: we don't care if we get an out of date allocation here
7251    * because clutter_actor_queue_redraw_with_clip knows to ignore
7252    * the clip if the actor's allocation is invalid.
7253    *
7254    * This is noted because clutter_actor_get_allocation_box does some
7255    * unnecessary work to support buggy code with a comment suggesting
7256    * that it could be changed later which would be good for this use
7257    * case!
7258    */
7259   clutter_actor_get_allocation_box (self, &allocation);
7260
7261   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7262    * actor's own coordinate space but the allocation is in parent
7263    * coordinates */
7264   clip->x1 = 0;
7265   clip->y1 = 0;
7266   clip->x2 = allocation.x2 - allocation.x1;
7267   clip->y2 = allocation.y2 - allocation.y1;
7268 }
7269
7270 void
7271 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7272                                   ClutterRedrawFlags  flags,
7273                                   ClutterPaintVolume *volume,
7274                                   ClutterEffect      *effect)
7275 {
7276   ClutterActorPrivate *priv = self->priv;
7277   ClutterPaintVolume allocation_pv;
7278   ClutterPaintVolume *pv;
7279   gboolean should_free_pv;
7280   ClutterActor *stage;
7281
7282   /* Here's an outline of the actor queue redraw mechanism:
7283    *
7284    * The process starts in one of the following two functions which
7285    * are wrappers for this function:
7286    * clutter_actor_queue_redraw
7287    * _clutter_actor_queue_redraw_with_clip
7288    *
7289    * additionally, an effect can queue a redraw by wrapping this
7290    * function in clutter_effect_queue_rerun
7291    *
7292    * This functions queues an entry in a list associated with the
7293    * stage which is a list of actors that queued a redraw while
7294    * updating the timelines, performing layouting and processing other
7295    * mainloop sources before the next paint starts.
7296    *
7297    * We aim to minimize the processing done at this point because
7298    * there is a good chance other events will happen while updating
7299    * the scenegraph that would invalidate any expensive work we might
7300    * otherwise try to do here. For example we don't try and resolve
7301    * the screen space bounding box of an actor at this stage so as to
7302    * minimize how much of the screen redraw because it's possible
7303    * something else will happen which will force a full redraw anyway.
7304    *
7305    * When all updates are complete and we come to paint the stage then
7306    * we iterate this list and actually emit the "queue-redraw" signals
7307    * for each of the listed actors which will bubble up to the stage
7308    * for each actor and at that point we will transform the actors
7309    * paint volume into screen coordinates to determine the clip region
7310    * for what needs to be redrawn in the next paint.
7311    *
7312    * Besides minimizing redundant work another reason for this
7313    * deferred design is that it's more likely we will be able to
7314    * determine the paint volume of an actor once we've finished
7315    * updating the scenegraph because its allocation should be up to
7316    * date. NB: If we can't determine an actors paint volume then we
7317    * can't automatically queue a clipped redraw which can make a big
7318    * difference to performance.
7319    *
7320    * So the control flow goes like this:
7321    * One of clutter_actor_queue_redraw,
7322    *        _clutter_actor_queue_redraw_with_clip
7323    *     or clutter_effect_queue_rerun
7324    *
7325    * then control moves to:
7326    *   _clutter_stage_queue_actor_redraw
7327    *
7328    * later during _clutter_stage_do_update, once relayouting is done
7329    * and the scenegraph has been updated we will call:
7330    * _clutter_stage_finish_queue_redraws
7331    *
7332    * _clutter_stage_finish_queue_redraws will call
7333    * _clutter_actor_finish_queue_redraw for each listed actor.
7334    * Note: actors *are* allowed to queue further redraws during this
7335    * process (considering clone actors or texture_new_from_actor which
7336    * respond to their source queueing a redraw by queuing a redraw
7337    * themselves). We repeat the process until the list is empty.
7338    *
7339    * This will result in the "queue-redraw" signal being fired for
7340    * each actor which will pass control to the default signal handler:
7341    * clutter_actor_real_queue_redraw
7342    *
7343    * This will bubble up to the stages handler:
7344    * clutter_stage_real_queue_redraw
7345    *
7346    * clutter_stage_real_queue_redraw will transform the actors paint
7347    * volume into screen space and add it as a clip region for the next
7348    * paint.
7349    */
7350
7351   /* ignore queueing a redraw for actors being destroyed */
7352   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7353     return;
7354
7355   stage = _clutter_actor_get_stage_internal (self);
7356
7357   /* Ignore queueing a redraw for actors not descended from a stage */
7358   if (stage == NULL)
7359     return;
7360
7361   /* ignore queueing a redraw on stages that are being destroyed */
7362   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7363     return;
7364
7365   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7366     {
7367       ClutterActorBox allocation_clip;
7368       ClutterVertex origin;
7369
7370       /* If the actor doesn't have a valid allocation then we will
7371        * queue a full stage redraw. */
7372       if (priv->needs_allocation)
7373         {
7374           /* NB: NULL denotes an undefined clip which will result in a
7375            * full redraw... */
7376           _clutter_actor_set_queue_redraw_clip (self, NULL);
7377           _clutter_actor_signal_queue_redraw (self, self);
7378           return;
7379         }
7380
7381       _clutter_paint_volume_init_static (&allocation_pv, self);
7382       pv = &allocation_pv;
7383
7384       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7385
7386       origin.x = allocation_clip.x1;
7387       origin.y = allocation_clip.y1;
7388       origin.z = 0;
7389       clutter_paint_volume_set_origin (pv, &origin);
7390       clutter_paint_volume_set_width (pv,
7391                                       allocation_clip.x2 - allocation_clip.x1);
7392       clutter_paint_volume_set_height (pv,
7393                                        allocation_clip.y2 -
7394                                        allocation_clip.y1);
7395       should_free_pv = TRUE;
7396     }
7397   else
7398     {
7399       pv = volume;
7400       should_free_pv = FALSE;
7401     }
7402
7403   self->priv->queue_redraw_entry =
7404     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7405                                        priv->queue_redraw_entry,
7406                                        self,
7407                                        pv);
7408
7409   if (should_free_pv)
7410     clutter_paint_volume_free (pv);
7411
7412   /* If this is the first redraw queued then we can directly use the
7413      effect parameter */
7414   if (!priv->is_dirty)
7415     priv->effect_to_redraw = effect;
7416   /* Otherwise we need to merge it with the existing effect parameter */
7417   else if (effect != NULL)
7418     {
7419       /* If there's already an effect then we need to use whichever is
7420          later in the chain of actors. Otherwise a full redraw has
7421          already been queued on the actor so we need to ignore the
7422          effect parameter */
7423       if (priv->effect_to_redraw != NULL)
7424         {
7425           if (priv->effects == NULL)
7426             g_warning ("Redraw queued with an effect that is "
7427                        "not applied to the actor");
7428           else
7429             {
7430               const GList *l;
7431
7432               for (l = _clutter_meta_group_peek_metas (priv->effects);
7433                    l != NULL;
7434                    l = l->next)
7435                 {
7436                   if (l->data == priv->effect_to_redraw ||
7437                       l->data == effect)
7438                     priv->effect_to_redraw = l->data;
7439                 }
7440             }
7441         }
7442     }
7443   else
7444     {
7445       /* If no effect is specified then we need to redraw the whole
7446          actor */
7447       priv->effect_to_redraw = NULL;
7448     }
7449
7450   priv->is_dirty = TRUE;
7451 }
7452
7453 /**
7454  * clutter_actor_queue_redraw:
7455  * @self: A #ClutterActor
7456  *
7457  * Queues up a redraw of an actor and any children. The redraw occurs
7458  * once the main loop becomes idle (after the current batch of events
7459  * has been processed, roughly).
7460  *
7461  * Applications rarely need to call this, as redraws are handled
7462  * automatically by modification functions.
7463  *
7464  * This function will not do anything if @self is not visible, or
7465  * if the actor is inside an invisible part of the scenegraph.
7466  *
7467  * Also be aware that painting is a NOP for actors with an opacity of
7468  * 0
7469  *
7470  * When you are implementing a custom actor you must queue a redraw
7471  * whenever some private state changes that will affect painting or
7472  * picking of your actor.
7473  */
7474 void
7475 clutter_actor_queue_redraw (ClutterActor *self)
7476 {
7477   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7478
7479   _clutter_actor_queue_redraw_full (self,
7480                                     0, /* flags */
7481                                     NULL, /* clip volume */
7482                                     NULL /* effect */);
7483 }
7484
7485 /*< private >
7486  * _clutter_actor_queue_redraw_with_clip:
7487  * @self: A #ClutterActor
7488  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7489  *   this queue redraw.
7490  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7491  *   redrawn or %NULL if you are just using a @flag to state your
7492  *   desired clipping.
7493  *
7494  * Queues up a clipped redraw of an actor and any children. The redraw
7495  * occurs once the main loop becomes idle (after the current batch of
7496  * events has been processed, roughly).
7497  *
7498  * If no flags are given the clip volume is defined by @volume
7499  * specified in actor coordinates and tells Clutter that only content
7500  * within this volume has been changed so Clutter can optionally
7501  * optimize the redraw.
7502  *
7503  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7504  * should be %NULL and this tells Clutter to use the actor's current
7505  * allocation as a clip box. This flag can only be used for 2D actors,
7506  * because any actor with depth may be projected outside its
7507  * allocation.
7508  *
7509  * Applications rarely need to call this, as redraws are handled
7510  * automatically by modification functions.
7511  *
7512  * This function will not do anything if @self is not visible, or if
7513  * the actor is inside an invisible part of the scenegraph.
7514  *
7515  * Also be aware that painting is a NOP for actors with an opacity of
7516  * 0
7517  *
7518  * When you are implementing a custom actor you must queue a redraw
7519  * whenever some private state changes that will affect painting or
7520  * picking of your actor.
7521  */
7522 void
7523 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7524                                        ClutterRedrawFlags  flags,
7525                                        ClutterPaintVolume *volume)
7526 {
7527   _clutter_actor_queue_redraw_full (self,
7528                                     flags, /* flags */
7529                                     volume, /* clip volume */
7530                                     NULL /* effect */);
7531 }
7532
7533 static void
7534 _clutter_actor_queue_only_relayout (ClutterActor *self)
7535 {
7536   ClutterActorPrivate *priv = self->priv;
7537
7538   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7539     return;
7540
7541   if (priv->needs_width_request &&
7542       priv->needs_height_request &&
7543       priv->needs_allocation)
7544     return; /* save some cpu cycles */
7545
7546 #if CLUTTER_ENABLE_DEBUG
7547   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7548     {
7549       g_warning ("The actor '%s' is currently inside an allocation "
7550                  "cycle; calling clutter_actor_queue_relayout() is "
7551                  "not recommended",
7552                  _clutter_actor_get_debug_name (self));
7553     }
7554 #endif /* CLUTTER_ENABLE_DEBUG */
7555
7556   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7557 }
7558
7559 /**
7560  * clutter_actor_queue_redraw_with_clip:
7561  * @self: a #ClutterActor
7562  * @clip: (allow-none): a rectangular clip region, or %NULL
7563  *
7564  * Queues a redraw on @self limited to a specific, actor-relative
7565  * rectangular area.
7566  *
7567  * If @clip is %NULL this function is equivalent to
7568  * clutter_actor_queue_redraw().
7569  *
7570  * Since: 1.10
7571  */
7572 void
7573 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7574                                       const cairo_rectangle_int_t *clip)
7575 {
7576   ClutterPaintVolume volume;
7577   ClutterVertex origin;
7578
7579   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7580
7581   if (clip == NULL)
7582     {
7583       clutter_actor_queue_redraw (self);
7584       return;
7585     }
7586
7587   _clutter_paint_volume_init_static (&volume, self);
7588
7589   origin.x = clip->x;
7590   origin.y = clip->y;
7591   origin.z = 0.0f;
7592
7593   clutter_paint_volume_set_origin (&volume, &origin);
7594   clutter_paint_volume_set_width (&volume, clip->width);
7595   clutter_paint_volume_set_height (&volume, clip->height);
7596
7597   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7598
7599   clutter_paint_volume_free (&volume);
7600 }
7601
7602 /**
7603  * clutter_actor_queue_relayout:
7604  * @self: A #ClutterActor
7605  *
7606  * Indicates that the actor's size request or other layout-affecting
7607  * properties may have changed. This function is used inside #ClutterActor
7608  * subclass implementations, not by applications directly.
7609  *
7610  * Queueing a new layout automatically queues a redraw as well.
7611  *
7612  * Since: 0.8
7613  */
7614 void
7615 clutter_actor_queue_relayout (ClutterActor *self)
7616 {
7617   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7618
7619   _clutter_actor_queue_only_relayout (self);
7620   clutter_actor_queue_redraw (self);
7621 }
7622
7623 /**
7624  * clutter_actor_get_preferred_size:
7625  * @self: a #ClutterActor
7626  * @min_width_p: (out) (allow-none): return location for the minimum
7627  *   width, or %NULL
7628  * @min_height_p: (out) (allow-none): return location for the minimum
7629  *   height, or %NULL
7630  * @natural_width_p: (out) (allow-none): return location for the natural
7631  *   width, or %NULL
7632  * @natural_height_p: (out) (allow-none): return location for the natural
7633  *   height, or %NULL
7634  *
7635  * Computes the preferred minimum and natural size of an actor, taking into
7636  * account the actor's geometry management (either height-for-width
7637  * or width-for-height).
7638  *
7639  * The width and height used to compute the preferred height and preferred
7640  * width are the actor's natural ones.
7641  *
7642  * If you need to control the height for the preferred width, or the width for
7643  * the preferred height, you should use clutter_actor_get_preferred_width()
7644  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7645  * geometry management using the #ClutterActor:request-mode property.
7646  *
7647  * Since: 0.8
7648  */
7649 void
7650 clutter_actor_get_preferred_size (ClutterActor *self,
7651                                   gfloat       *min_width_p,
7652                                   gfloat       *min_height_p,
7653                                   gfloat       *natural_width_p,
7654                                   gfloat       *natural_height_p)
7655 {
7656   ClutterActorPrivate *priv;
7657   gfloat min_width, min_height;
7658   gfloat natural_width, natural_height;
7659
7660   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7661
7662   priv = self->priv;
7663
7664   min_width = min_height = 0;
7665   natural_width = natural_height = 0;
7666
7667   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7668     {
7669       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7670       clutter_actor_get_preferred_width (self, -1,
7671                                          &min_width,
7672                                          &natural_width);
7673       clutter_actor_get_preferred_height (self, natural_width,
7674                                           &min_height,
7675                                           &natural_height);
7676     }
7677   else
7678     {
7679       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7680       clutter_actor_get_preferred_height (self, -1,
7681                                           &min_height,
7682                                           &natural_height);
7683       clutter_actor_get_preferred_width (self, natural_height,
7684                                          &min_width,
7685                                          &natural_width);
7686     }
7687
7688   if (min_width_p)
7689     *min_width_p = min_width;
7690
7691   if (min_height_p)
7692     *min_height_p = min_height;
7693
7694   if (natural_width_p)
7695     *natural_width_p = natural_width;
7696
7697   if (natural_height_p)
7698     *natural_height_p = natural_height;
7699 }
7700
7701 /*< private >
7702  * effective_align:
7703  * @align: a #ClutterActorAlign
7704  * @direction: a #ClutterTextDirection
7705  *
7706  * Retrieves the correct alignment depending on the text direction
7707  *
7708  * Return value: the effective alignment
7709  */
7710 static ClutterActorAlign
7711 effective_align (ClutterActorAlign    align,
7712                  ClutterTextDirection direction)
7713 {
7714   ClutterActorAlign res;
7715
7716   switch (align)
7717     {
7718     case CLUTTER_ACTOR_ALIGN_START:
7719       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7720           ? CLUTTER_ACTOR_ALIGN_END
7721           : CLUTTER_ACTOR_ALIGN_START;
7722       break;
7723
7724     case CLUTTER_ACTOR_ALIGN_END:
7725       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7726           ? CLUTTER_ACTOR_ALIGN_START
7727           : CLUTTER_ACTOR_ALIGN_END;
7728       break;
7729
7730     default:
7731       res = align;
7732       break;
7733     }
7734
7735   return res;
7736 }
7737
7738 static inline void
7739 adjust_for_margin (float  margin_start,
7740                    float  margin_end,
7741                    float *minimum_size,
7742                    float *natural_size,
7743                    float *allocated_start,
7744                    float *allocated_end)
7745 {
7746   *minimum_size -= (margin_start + margin_end);
7747   *natural_size -= (margin_start + margin_end);
7748   *allocated_start += margin_start;
7749   *allocated_end -= margin_end;
7750 }
7751
7752 static inline void
7753 adjust_for_alignment (ClutterActorAlign  alignment,
7754                       float              natural_size,
7755                       float             *allocated_start,
7756                       float             *allocated_end)
7757 {
7758   float allocated_size = *allocated_end - *allocated_start;
7759
7760   switch (alignment)
7761     {
7762     case CLUTTER_ACTOR_ALIGN_FILL:
7763       /* do nothing */
7764       break;
7765
7766     case CLUTTER_ACTOR_ALIGN_START:
7767       /* keep start */
7768       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7769       break;
7770
7771     case CLUTTER_ACTOR_ALIGN_END:
7772       if (allocated_size > natural_size)
7773         {
7774           *allocated_start += (allocated_size - natural_size);
7775           *allocated_end = *allocated_start + natural_size;
7776         }
7777       break;
7778
7779     case CLUTTER_ACTOR_ALIGN_CENTER:
7780       if (allocated_size > natural_size)
7781         {
7782           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7783           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7784         }
7785       break;
7786     }
7787 }
7788
7789 /*< private >
7790  * clutter_actor_adjust_width:
7791  * @self: a #ClutterActor
7792  * @minimum_width: (inout): the actor's preferred minimum width, which
7793  *   will be adjusted depending on the margin
7794  * @natural_width: (inout): the actor's preferred natural width, which
7795  *   will be adjusted depending on the margin
7796  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7797  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7798  *
7799  * Adjusts the preferred and allocated position and size of an actor,
7800  * depending on the margin and alignment properties.
7801  */
7802 static void
7803 clutter_actor_adjust_width (ClutterActor *self,
7804                             gfloat       *minimum_width,
7805                             gfloat       *natural_width,
7806                             gfloat       *adjusted_x1,
7807                             gfloat       *adjusted_x2)
7808 {
7809   ClutterTextDirection text_dir;
7810   const ClutterLayoutInfo *info;
7811
7812   info = _clutter_actor_get_layout_info_or_defaults (self);
7813   text_dir = clutter_actor_get_text_direction (self);
7814
7815   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7816
7817   /* this will tweak natural_width to remove the margin, so that
7818    * adjust_for_alignment() will use the correct size
7819    */
7820   adjust_for_margin (info->margin.left, info->margin.right,
7821                      minimum_width, natural_width,
7822                      adjusted_x1, adjusted_x2);
7823
7824   adjust_for_alignment (effective_align (info->x_align, text_dir),
7825                         *natural_width,
7826                         adjusted_x1, adjusted_x2);
7827 }
7828
7829 /*< private >
7830  * clutter_actor_adjust_height:
7831  * @self: a #ClutterActor
7832  * @minimum_height: (inout): the actor's preferred minimum height, which
7833  *   will be adjusted depending on the margin
7834  * @natural_height: (inout): the actor's preferred natural height, which
7835  *   will be adjusted depending on the margin
7836  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7837  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7838  *
7839  * Adjusts the preferred and allocated position and size of an actor,
7840  * depending on the margin and alignment properties.
7841  */
7842 static void
7843 clutter_actor_adjust_height (ClutterActor *self,
7844                              gfloat       *minimum_height,
7845                              gfloat       *natural_height,
7846                              gfloat       *adjusted_y1,
7847                              gfloat       *adjusted_y2)
7848 {
7849   const ClutterLayoutInfo *info;
7850
7851   info = _clutter_actor_get_layout_info_or_defaults (self);
7852
7853   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7854
7855   /* this will tweak natural_height to remove the margin, so that
7856    * adjust_for_alignment() will use the correct size
7857    */
7858   adjust_for_margin (info->margin.top, info->margin.bottom,
7859                      minimum_height, natural_height,
7860                      adjusted_y1,
7861                      adjusted_y2);
7862
7863   /* we don't use effective_align() here, because text direction
7864    * only affects the horizontal axis
7865    */
7866   adjust_for_alignment (info->y_align,
7867                         *natural_height,
7868                         adjusted_y1,
7869                         adjusted_y2);
7870
7871 }
7872
7873 /* looks for a cached size request for this for_size. If not
7874  * found, returns the oldest entry so it can be overwritten */
7875 static gboolean
7876 _clutter_actor_get_cached_size_request (gfloat         for_size,
7877                                         SizeRequest   *cached_size_requests,
7878                                         SizeRequest  **result)
7879 {
7880   guint i;
7881
7882   *result = &cached_size_requests[0];
7883
7884   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7885     {
7886       SizeRequest *sr;
7887
7888       sr = &cached_size_requests[i];
7889
7890       if (sr->age > 0 &&
7891           sr->for_size == for_size)
7892         {
7893           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7894           *result = sr;
7895           return TRUE;
7896         }
7897       else if (sr->age < (*result)->age)
7898         {
7899           *result = sr;
7900         }
7901     }
7902
7903   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7904
7905   return FALSE;
7906 }
7907
7908 /**
7909  * clutter_actor_get_preferred_width:
7910  * @self: A #ClutterActor
7911  * @for_height: available height when computing the preferred width,
7912  *   or a negative value to indicate that no height is defined
7913  * @min_width_p: (out) (allow-none): return location for minimum width,
7914  *   or %NULL
7915  * @natural_width_p: (out) (allow-none): return location for the natural
7916  *   width, or %NULL
7917  *
7918  * Computes the requested minimum and natural widths for an actor,
7919  * optionally depending on the specified height, or if they are
7920  * already computed, returns the cached values.
7921  *
7922  * An actor may not get its request - depending on the layout
7923  * manager that's in effect.
7924  *
7925  * A request should not incorporate the actor's scale or anchor point;
7926  * those transformations do not affect layout, only rendering.
7927  *
7928  * Since: 0.8
7929  */
7930 void
7931 clutter_actor_get_preferred_width (ClutterActor *self,
7932                                    gfloat        for_height,
7933                                    gfloat       *min_width_p,
7934                                    gfloat       *natural_width_p)
7935 {
7936   float request_min_width, request_natural_width;
7937   SizeRequest *cached_size_request;
7938   const ClutterLayoutInfo *info;
7939   ClutterActorPrivate *priv;
7940   gboolean found_in_cache;
7941
7942   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7943
7944   priv = self->priv;
7945
7946   info = _clutter_actor_get_layout_info_or_defaults (self);
7947
7948   /* we shortcircuit the case of a fixed size set using set_width() */
7949   if (priv->min_width_set && priv->natural_width_set)
7950     {
7951       if (min_width_p != NULL)
7952         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7953
7954       if (natural_width_p != NULL)
7955         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7956
7957       return;
7958     }
7959
7960   /* the remaining cases are:
7961    *
7962    *   - either min_width or natural_width have been set
7963    *   - neither min_width or natural_width have been set
7964    *
7965    * in both cases, we go through the cache (and through the actor in case
7966    * of cache misses) and determine the authoritative value depending on
7967    * the *_set flags.
7968    */
7969
7970   if (!priv->needs_width_request)
7971     {
7972       found_in_cache =
7973         _clutter_actor_get_cached_size_request (for_height,
7974                                                 priv->width_requests,
7975                                                 &cached_size_request);
7976     }
7977   else
7978     {
7979       /* if the actor needs a width request we use the first slot */
7980       found_in_cache = FALSE;
7981       cached_size_request = &priv->width_requests[0];
7982     }
7983
7984   if (!found_in_cache)
7985     {
7986       gfloat minimum_width, natural_width;
7987       ClutterActorClass *klass;
7988
7989       minimum_width = natural_width = 0;
7990
7991       /* adjust for the margin */
7992       if (for_height >= 0)
7993         {
7994           for_height -= (info->margin.top + info->margin.bottom);
7995           if (for_height < 0)
7996             for_height = 0;
7997         }
7998
7999       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8000
8001       klass = CLUTTER_ACTOR_GET_CLASS (self);
8002       klass->get_preferred_width (self, for_height,
8003                                   &minimum_width,
8004                                   &natural_width);
8005
8006       /* adjust for the margin */
8007       minimum_width += (info->margin.left + info->margin.right);
8008       natural_width += (info->margin.left + info->margin.right);
8009
8010       /* Due to accumulated float errors, it's better not to warn
8011        * on this, but just fix it.
8012        */
8013       if (natural_width < minimum_width)
8014         natural_width = minimum_width;
8015
8016       cached_size_request->min_size = minimum_width;
8017       cached_size_request->natural_size = natural_width;
8018       cached_size_request->for_size = for_height;
8019       cached_size_request->age = priv->cached_width_age;
8020
8021       priv->cached_width_age += 1;
8022       priv->needs_width_request = FALSE;
8023     }
8024
8025   if (!priv->min_width_set)
8026     request_min_width = cached_size_request->min_size;
8027   else
8028     request_min_width = info->min_width;
8029
8030   if (!priv->natural_width_set)
8031     request_natural_width = cached_size_request->natural_size;
8032   else
8033     request_natural_width = info->natural_width;
8034
8035   if (min_width_p)
8036     *min_width_p = request_min_width;
8037
8038   if (natural_width_p)
8039     *natural_width_p = request_natural_width;
8040 }
8041
8042 /**
8043  * clutter_actor_get_preferred_height:
8044  * @self: A #ClutterActor
8045  * @for_width: available width to assume in computing desired height,
8046  *   or a negative value to indicate that no width is defined
8047  * @min_height_p: (out) (allow-none): return location for minimum height,
8048  *   or %NULL
8049  * @natural_height_p: (out) (allow-none): return location for natural
8050  *   height, or %NULL
8051  *
8052  * Computes the requested minimum and natural heights for an actor,
8053  * or if they are already computed, returns the cached values.
8054  *
8055  * An actor may not get its request - depending on the layout
8056  * manager that's in effect.
8057  *
8058  * A request should not incorporate the actor's scale or anchor point;
8059  * those transformations do not affect layout, only rendering.
8060  *
8061  * Since: 0.8
8062  */
8063 void
8064 clutter_actor_get_preferred_height (ClutterActor *self,
8065                                     gfloat        for_width,
8066                                     gfloat       *min_height_p,
8067                                     gfloat       *natural_height_p)
8068 {
8069   float request_min_height, request_natural_height;
8070   SizeRequest *cached_size_request;
8071   const ClutterLayoutInfo *info;
8072   ClutterActorPrivate *priv;
8073   gboolean found_in_cache;
8074
8075   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8076
8077   priv = self->priv;
8078
8079   info = _clutter_actor_get_layout_info_or_defaults (self);
8080
8081   /* we shortcircuit the case of a fixed size set using set_height() */
8082   if (priv->min_height_set && priv->natural_height_set)
8083     {
8084       if (min_height_p != NULL)
8085         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
8086
8087       if (natural_height_p != NULL)
8088         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
8089
8090       return;
8091     }
8092
8093   /* the remaining cases are:
8094    *
8095    *   - either min_height or natural_height have been set
8096    *   - neither min_height or natural_height have been set
8097    *
8098    * in both cases, we go through the cache (and through the actor in case
8099    * of cache misses) and determine the authoritative value depending on
8100    * the *_set flags.
8101    */
8102
8103   if (!priv->needs_height_request)
8104     {
8105       found_in_cache =
8106         _clutter_actor_get_cached_size_request (for_width,
8107                                                 priv->height_requests,
8108                                                 &cached_size_request);
8109     }
8110   else
8111     {
8112       found_in_cache = FALSE;
8113       cached_size_request = &priv->height_requests[0];
8114     }
8115
8116   if (!found_in_cache)
8117     {
8118       gfloat minimum_height, natural_height;
8119       ClutterActorClass *klass;
8120
8121       minimum_height = natural_height = 0;
8122
8123       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8124
8125       /* adjust for margin */
8126       if (for_width >= 0)
8127         {
8128           for_width -= (info->margin.left + info->margin.right);
8129           if (for_width < 0)
8130             for_width = 0;
8131         }
8132
8133       klass = CLUTTER_ACTOR_GET_CLASS (self);
8134       klass->get_preferred_height (self, for_width,
8135                                    &minimum_height,
8136                                    &natural_height);
8137
8138       /* adjust for margin */
8139       minimum_height += (info->margin.top + info->margin.bottom);
8140       natural_height += (info->margin.top + info->margin.bottom);
8141
8142       /* Due to accumulated float errors, it's better not to warn
8143        * on this, but just fix it.
8144        */
8145       if (natural_height < minimum_height)
8146         natural_height = minimum_height;
8147
8148       cached_size_request->min_size = minimum_height;
8149       cached_size_request->natural_size = natural_height;
8150       cached_size_request->for_size = for_width;
8151       cached_size_request->age = priv->cached_height_age;
8152
8153       priv->cached_height_age += 1;
8154       priv->needs_height_request = FALSE;
8155     }
8156
8157   if (!priv->min_height_set)
8158     request_min_height = cached_size_request->min_size;
8159   else
8160     request_min_height = info->min_height;
8161
8162   if (!priv->natural_height_set)
8163     request_natural_height = cached_size_request->natural_size;
8164   else
8165     request_natural_height = info->natural_height;
8166
8167   if (min_height_p)
8168     *min_height_p = request_min_height;
8169
8170   if (natural_height_p)
8171     *natural_height_p = request_natural_height;
8172 }
8173
8174 /**
8175  * clutter_actor_get_allocation_box:
8176  * @self: A #ClutterActor
8177  * @box: (out): the function fills this in with the actor's allocation
8178  *
8179  * Gets the layout box an actor has been assigned. The allocation can
8180  * only be assumed valid inside a paint() method; anywhere else, it
8181  * may be out-of-date.
8182  *
8183  * An allocation does not incorporate the actor's scale or anchor point;
8184  * those transformations do not affect layout, only rendering.
8185  *
8186  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8187  * of functions inside the implementation of the get_preferred_width()
8188  * or get_preferred_height() virtual functions.</note>
8189  *
8190  * Since: 0.8
8191  */
8192 void
8193 clutter_actor_get_allocation_box (ClutterActor    *self,
8194                                   ClutterActorBox *box)
8195 {
8196   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8197
8198   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8199    * which limits calling get_allocation to inside paint() basically; or
8200    * we can 2) force a layout, which could be expensive if someone calls
8201    * get_allocation somewhere silly; or we can 3) just return the latest
8202    * value, allowing it to be out-of-date, and assume people know what
8203    * they are doing.
8204    *
8205    * The least-surprises approach that keeps existing code working is
8206    * likely to be 2). People can end up doing some inefficient things,
8207    * though, and in general code that requires 2) is probably broken.
8208    */
8209
8210   /* this implements 2) */
8211   if (G_UNLIKELY (self->priv->needs_allocation))
8212     {
8213       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8214
8215       /* do not queue a relayout on an unparented actor */
8216       if (stage)
8217         _clutter_stage_maybe_relayout (stage);
8218     }
8219
8220   /* commenting out the code above and just keeping this assigment
8221    * implements 3)
8222    */
8223   *box = self->priv->allocation;
8224 }
8225
8226 /**
8227  * clutter_actor_get_allocation_geometry:
8228  * @self: A #ClutterActor
8229  * @geom: (out): allocation geometry in pixels
8230  *
8231  * Gets the layout box an actor has been assigned.  The allocation can
8232  * only be assumed valid inside a paint() method; anywhere else, it
8233  * may be out-of-date.
8234  *
8235  * An allocation does not incorporate the actor's scale or anchor point;
8236  * those transformations do not affect layout, only rendering.
8237  *
8238  * The returned rectangle is in pixels.
8239  *
8240  * Since: 0.8
8241  */
8242 void
8243 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8244                                        ClutterGeometry *geom)
8245 {
8246   ClutterActorBox box;
8247
8248   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8249   g_return_if_fail (geom != NULL);
8250
8251   clutter_actor_get_allocation_box (self, &box);
8252
8253   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8254   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8255   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8256   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8257 }
8258
8259 static void
8260 clutter_actor_update_constraints (ClutterActor    *self,
8261                                   ClutterActorBox *allocation)
8262 {
8263   ClutterActorPrivate *priv = self->priv;
8264   const GList *constraints, *l;
8265
8266   if (priv->constraints == NULL)
8267     return;
8268
8269   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8270   for (l = constraints; l != NULL; l = l->next)
8271     {
8272       ClutterConstraint *constraint = l->data;
8273       ClutterActorMeta *meta = l->data;
8274
8275       if (clutter_actor_meta_get_enabled (meta))
8276         {
8277           _clutter_constraint_update_allocation (constraint,
8278                                                  self,
8279                                                  allocation);
8280
8281           CLUTTER_NOTE (LAYOUT,
8282                         "Allocation of '%s' after constraint '%s': "
8283                         "{ %.2f, %.2f, %.2f, %.2f }",
8284                         _clutter_actor_get_debug_name (self),
8285                         _clutter_actor_meta_get_debug_name (meta),
8286                         allocation->x1,
8287                         allocation->y1,
8288                         allocation->x2,
8289                         allocation->y2);
8290         }
8291     }
8292 }
8293
8294 /*< private >
8295  * clutter_actor_adjust_allocation:
8296  * @self: a #ClutterActor
8297  * @allocation: (inout): the allocation to adjust
8298  *
8299  * Adjusts the passed allocation box taking into account the actor's
8300  * layout information, like alignment, expansion, and margin.
8301  */
8302 static void
8303 clutter_actor_adjust_allocation (ClutterActor    *self,
8304                                  ClutterActorBox *allocation)
8305 {
8306   ClutterActorBox adj_allocation;
8307   float alloc_width, alloc_height;
8308   float min_width, min_height;
8309   float nat_width, nat_height;
8310   ClutterRequestMode req_mode;
8311
8312   adj_allocation = *allocation;
8313
8314   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8315
8316   /* we want to hit the cache, so we use the public API */
8317   req_mode = clutter_actor_get_request_mode (self);
8318
8319   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8320     {
8321       clutter_actor_get_preferred_width (self, -1,
8322                                          &min_width,
8323                                          &nat_width);
8324       clutter_actor_get_preferred_height (self, alloc_width,
8325                                           &min_height,
8326                                           &nat_height);
8327     }
8328   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8329     {
8330       clutter_actor_get_preferred_height (self, -1,
8331                                           &min_height,
8332                                           &nat_height);
8333       clutter_actor_get_preferred_height (self, alloc_height,
8334                                           &min_width,
8335                                           &nat_width);
8336     }
8337
8338 #ifdef CLUTTER_ENABLE_DEBUG
8339   /* warn about underallocations */
8340   if (_clutter_diagnostic_enabled () &&
8341       (floorf (min_width - alloc_width) > 0 ||
8342        floorf (min_height - alloc_height) > 0))
8343     {
8344       ClutterActor *parent = clutter_actor_get_parent (self);
8345
8346       /* the only actors that are allowed to be underallocated are the Stage,
8347        * as it doesn't have an implicit size, and Actors that specifically
8348        * told us that they want to opt-out from layout control mechanisms
8349        * through the NO_LAYOUT escape hatch.
8350        */
8351       if (parent != NULL &&
8352           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8353         {
8354           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8355                      "of %.2f x %.2f from its parent actor '%s', but its "
8356                      "requested minimum size is of %.2f x %.2f",
8357                      _clutter_actor_get_debug_name (self),
8358                      alloc_width, alloc_height,
8359                      _clutter_actor_get_debug_name (parent),
8360                      min_width, min_height);
8361         }
8362     }
8363 #endif
8364
8365   clutter_actor_adjust_width (self,
8366                               &min_width,
8367                               &nat_width,
8368                               &adj_allocation.x1,
8369                               &adj_allocation.x2);
8370
8371   clutter_actor_adjust_height (self,
8372                                &min_height,
8373                                &nat_height,
8374                                &adj_allocation.y1,
8375                                &adj_allocation.y2);
8376
8377   /* we maintain the invariant that an allocation cannot be adjusted
8378    * to be outside the parent-given box
8379    */
8380   if (adj_allocation.x1 < allocation->x1 ||
8381       adj_allocation.y1 < allocation->y1 ||
8382       adj_allocation.x2 > allocation->x2 ||
8383       adj_allocation.y2 > allocation->y2)
8384     {
8385       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8386                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8387                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8388                  _clutter_actor_get_debug_name (self),
8389                  adj_allocation.x1, adj_allocation.y1,
8390                  adj_allocation.x2 - adj_allocation.x1,
8391                  adj_allocation.y2 - adj_allocation.y1,
8392                  allocation->x1, allocation->y1,
8393                  allocation->x2 - allocation->x1,
8394                  allocation->y2 - allocation->y1);
8395       return;
8396     }
8397
8398   *allocation = adj_allocation;
8399 }
8400
8401 /**
8402  * clutter_actor_allocate:
8403  * @self: A #ClutterActor
8404  * @box: new allocation of the actor, in parent-relative coordinates
8405  * @flags: flags that control the allocation
8406  *
8407  * Called by the parent of an actor to assign the actor its size.
8408  * Should never be called by applications (except when implementing
8409  * a container or layout manager).
8410  *
8411  * Actors can know from their allocation box whether they have moved
8412  * with respect to their parent actor. The @flags parameter describes
8413  * additional information about the allocation, for instance whether
8414  * the parent has moved with respect to the stage, for example because
8415  * a grandparent's origin has moved.
8416  *
8417  * Since: 0.8
8418  */
8419 void
8420 clutter_actor_allocate (ClutterActor           *self,
8421                         const ClutterActorBox  *box,
8422                         ClutterAllocationFlags  flags)
8423 {
8424   ClutterActorPrivate *priv;
8425   ClutterActorClass *klass;
8426   ClutterActorBox old_allocation, real_allocation;
8427   gboolean origin_changed, child_moved, size_changed;
8428   gboolean stage_allocation_changed;
8429
8430   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8431   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8432     {
8433       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8434                  "which isn't a descendent of the stage!\n",
8435                  self, _clutter_actor_get_debug_name (self));
8436       return;
8437     }
8438
8439   priv = self->priv;
8440
8441   old_allocation = priv->allocation;
8442   real_allocation = *box;
8443
8444   /* constraints are allowed to modify the allocation only here; we do
8445    * this prior to all the other checks so that we can bail out if the
8446    * allocation did not change
8447    */
8448   clutter_actor_update_constraints (self, &real_allocation);
8449
8450   /* adjust the allocation depending on the align/margin properties */
8451   clutter_actor_adjust_allocation (self, &real_allocation);
8452
8453   if (real_allocation.x2 < real_allocation.x1 ||
8454       real_allocation.y2 < real_allocation.y1)
8455     {
8456       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8457                  _clutter_actor_get_debug_name (self),
8458                  real_allocation.x2 - real_allocation.x1,
8459                  real_allocation.y2 - real_allocation.y1);
8460     }
8461
8462   /* we allow 0-sized actors, but not negative-sized ones */
8463   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8464   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8465
8466   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8467
8468   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8469                  real_allocation.y1 != old_allocation.y1);
8470
8471   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8472                   real_allocation.y2 != old_allocation.y2);
8473
8474   if (origin_changed || child_moved || size_changed)
8475     stage_allocation_changed = TRUE;
8476   else
8477     stage_allocation_changed = FALSE;
8478
8479   /* If we get an allocation "out of the blue"
8480    * (we did not queue relayout), then we want to
8481    * ignore it. But if we have needs_allocation set,
8482    * we want to guarantee that allocate() virtual
8483    * method is always called, i.e. that queue_relayout()
8484    * always results in an allocate() invocation on
8485    * an actor.
8486    *
8487    * The optimization here is to avoid re-allocating
8488    * actors that did not queue relayout and were
8489    * not moved.
8490    */
8491   if (!priv->needs_allocation && !stage_allocation_changed)
8492     {
8493       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8494       return;
8495     }
8496
8497   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8498    * clutter_actor_allocate(), it indicates whether the parent has its
8499    * absolute origin moved; when passed in to ClutterActor::allocate()
8500    * virtual method though, it indicates whether the child has its
8501    * absolute origin moved.  So we set it when child_moved is TRUE
8502    */
8503   if (child_moved)
8504     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8505
8506   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8507
8508   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8509                 _clutter_actor_get_debug_name (self));
8510
8511   klass = CLUTTER_ACTOR_GET_CLASS (self);
8512   klass->allocate (self, &real_allocation, flags);
8513
8514   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8515
8516   if (stage_allocation_changed)
8517     clutter_actor_queue_redraw (self);
8518 }
8519
8520 /**
8521  * clutter_actor_set_allocation:
8522  * @self: a #ClutterActor
8523  * @box: a #ClutterActorBox
8524  * @flags: allocation flags
8525  *
8526  * Stores the allocation of @self as defined by @box.
8527  *
8528  * This function can only be called from within the implementation of
8529  * the #ClutterActorClass.allocate() virtual function.
8530  *
8531  * The allocation should have been adjusted to take into account constraints,
8532  * alignment, and margin properties. If you are implementing a #ClutterActor
8533  * subclass that provides its own layout management policy for its children
8534  * instead of using a #ClutterLayoutManager delegate, you should not call
8535  * this function on the children of @self; instead, you should call
8536  * clutter_actor_allocate(), which will adjust the allocation box for
8537  * you.
8538  *
8539  * This function should only be used by subclasses of #ClutterActor
8540  * that wish to store their allocation but cannot chain up to the
8541  * parent's implementation; the default implementation of the
8542  * #ClutterActorClass.allocate() virtual function will call this
8543  * function.
8544  *
8545  * It is important to note that, while chaining up was the recommended
8546  * behaviour for #ClutterActor subclasses prior to the introduction of
8547  * this function, it is recommended to call clutter_actor_set_allocation()
8548  * instead.
8549  *
8550  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8551  * to handle the allocation of its children, this function will call
8552  * the clutter_layout_manager_allocate() function only if the
8553  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8554  * expected that the subclass will call clutter_layout_manager_allocate()
8555  * by itself. For instance, the following code:
8556  *
8557  * |[
8558  * static void
8559  * my_actor_allocate (ClutterActor *actor,
8560  *                    const ClutterActorBox *allocation,
8561  *                    ClutterAllocationFlags flags)
8562  * {
8563  *   ClutterActorBox new_alloc;
8564  *   ClutterAllocationFlags new_flags;
8565  *
8566  *   adjust_allocation (allocation, &amp;new_alloc);
8567  *
8568  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8569  *
8570  *   /&ast; this will use the layout manager set on the actor &ast;/
8571  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8572  * }
8573  * ]|
8574  *
8575  * is equivalent to this:
8576  *
8577  * |[
8578  * static void
8579  * my_actor_allocate (ClutterActor *actor,
8580  *                    const ClutterActorBox *allocation,
8581  *                    ClutterAllocationFlags flags)
8582  * {
8583  *   ClutterLayoutManager *layout;
8584  *   ClutterActorBox new_alloc;
8585  *
8586  *   adjust_allocation (allocation, &amp;new_alloc);
8587  *
8588  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8589  *
8590  *   layout = clutter_actor_get_layout_manager (actor);
8591  *   clutter_layout_manager_allocate (layout,
8592  *                                    CLUTTER_CONTAINER (actor),
8593  *                                    &amp;new_alloc,
8594  *                                    flags);
8595  * }
8596  * ]|
8597  *
8598  * Since: 1.10
8599  */
8600 void
8601 clutter_actor_set_allocation (ClutterActor           *self,
8602                               const ClutterActorBox  *box,
8603                               ClutterAllocationFlags  flags)
8604 {
8605   ClutterActorPrivate *priv;
8606   gboolean changed;
8607
8608   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8609   g_return_if_fail (box != NULL);
8610
8611   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8612     {
8613       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8614                   "can only be called from within the implementation of "
8615                   "the ClutterActor::allocate() virtual function.");
8616       return;
8617     }
8618
8619   priv = self->priv;
8620
8621   g_object_freeze_notify (G_OBJECT (self));
8622
8623   changed = clutter_actor_set_allocation_internal (self, box, flags);
8624
8625   /* we allocate our children before we notify changes in our geometry,
8626    * so that people connecting to properties will be able to get valid
8627    * data out of the sub-tree of the scene graph that has this actor at
8628    * the root.
8629    */
8630   clutter_actor_maybe_layout_children (self, box, flags);
8631
8632   if (changed)
8633     {
8634       ClutterActorBox signal_box = priv->allocation;
8635       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8636
8637       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8638                      &signal_box,
8639                      signal_flags);
8640     }
8641
8642   g_object_thaw_notify (G_OBJECT (self));
8643 }
8644
8645 /**
8646  * clutter_actor_set_geometry:
8647  * @self: A #ClutterActor
8648  * @geometry: A #ClutterGeometry
8649  *
8650  * Sets the actor's fixed position and forces its minimum and natural
8651  * size, in pixels. This means the untransformed actor will have the
8652  * given geometry. This is the same as calling clutter_actor_set_position()
8653  * and clutter_actor_set_size().
8654  *
8655  * Deprecated: 1.10: Use clutter_actor_set_position() and
8656  *   clutter_actor_set_size() instead.
8657  */
8658 void
8659 clutter_actor_set_geometry (ClutterActor          *self,
8660                             const ClutterGeometry *geometry)
8661 {
8662   g_object_freeze_notify (G_OBJECT (self));
8663
8664   clutter_actor_set_position (self, geometry->x, geometry->y);
8665   clutter_actor_set_size (self, geometry->width, geometry->height);
8666
8667   g_object_thaw_notify (G_OBJECT (self));
8668 }
8669
8670 /**
8671  * clutter_actor_get_geometry:
8672  * @self: A #ClutterActor
8673  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8674  *
8675  * Gets the size and position of an actor relative to its parent
8676  * actor. This is the same as calling clutter_actor_get_position() and
8677  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8678  * requested size and position if the actor's allocation is invalid.
8679  *
8680  * Deprecated: 1.10: Use clutter_actor_get_position() and
8681  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8682  *   instead.
8683  */
8684 void
8685 clutter_actor_get_geometry (ClutterActor    *self,
8686                             ClutterGeometry *geometry)
8687 {
8688   gfloat x, y, width, height;
8689
8690   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8691   g_return_if_fail (geometry != NULL);
8692
8693   clutter_actor_get_position (self, &x, &y);
8694   clutter_actor_get_size (self, &width, &height);
8695
8696   geometry->x = (int) x;
8697   geometry->y = (int) y;
8698   geometry->width = (int) width;
8699   geometry->height = (int) height;
8700 }
8701
8702 /**
8703  * clutter_actor_set_position:
8704  * @self: A #ClutterActor
8705  * @x: New left position of actor in pixels.
8706  * @y: New top position of actor in pixels.
8707  *
8708  * Sets the actor's fixed position in pixels relative to any parent
8709  * actor.
8710  *
8711  * If a layout manager is in use, this position will override the
8712  * layout manager and force a fixed position.
8713  */
8714 void
8715 clutter_actor_set_position (ClutterActor *self,
8716                             gfloat        x,
8717                             gfloat        y)
8718 {
8719   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8720
8721   g_object_freeze_notify (G_OBJECT (self));
8722
8723   clutter_actor_set_x (self, x);
8724   clutter_actor_set_y (self, y);
8725
8726   g_object_thaw_notify (G_OBJECT (self));
8727 }
8728
8729 /**
8730  * clutter_actor_get_fixed_position_set:
8731  * @self: A #ClutterActor
8732  *
8733  * Checks whether an actor has a fixed position set (and will thus be
8734  * unaffected by any layout manager).
8735  *
8736  * Return value: %TRUE if the fixed position is set on the actor
8737  *
8738  * Since: 0.8
8739  */
8740 gboolean
8741 clutter_actor_get_fixed_position_set (ClutterActor *self)
8742 {
8743   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8744
8745   return self->priv->position_set;
8746 }
8747
8748 /**
8749  * clutter_actor_set_fixed_position_set:
8750  * @self: A #ClutterActor
8751  * @is_set: whether to use fixed position
8752  *
8753  * Sets whether an actor has a fixed position set (and will thus be
8754  * unaffected by any layout manager).
8755  *
8756  * Since: 0.8
8757  */
8758 void
8759 clutter_actor_set_fixed_position_set (ClutterActor *self,
8760                                       gboolean      is_set)
8761 {
8762   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8763
8764   if (self->priv->position_set == (is_set != FALSE))
8765     return;
8766
8767   self->priv->position_set = is_set != FALSE;
8768   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8769
8770   clutter_actor_queue_relayout (self);
8771 }
8772
8773 /**
8774  * clutter_actor_move_by:
8775  * @self: A #ClutterActor
8776  * @dx: Distance to move Actor on X axis.
8777  * @dy: Distance to move Actor on Y axis.
8778  *
8779  * Moves an actor by the specified distance relative to its current
8780  * position in pixels.
8781  *
8782  * This function modifies the fixed position of an actor and thus removes
8783  * it from any layout management. Another way to move an actor is with an
8784  * anchor point, see clutter_actor_set_anchor_point().
8785  *
8786  * Since: 0.2
8787  */
8788 void
8789 clutter_actor_move_by (ClutterActor *self,
8790                        gfloat        dx,
8791                        gfloat        dy)
8792 {
8793   const ClutterLayoutInfo *info;
8794   gfloat x, y;
8795
8796   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8797
8798   info = _clutter_actor_get_layout_info_or_defaults (self);
8799   x = info->fixed_x;
8800   y = info->fixed_y;
8801
8802   clutter_actor_set_position (self, x + dx, y + dy);
8803 }
8804
8805 static void
8806 clutter_actor_set_min_width (ClutterActor *self,
8807                              gfloat        min_width)
8808 {
8809   ClutterActorPrivate *priv = self->priv;
8810   ClutterActorBox old = { 0, };
8811   ClutterLayoutInfo *info;
8812
8813   /* if we are setting the size on a top-level actor and the
8814    * backend only supports static top-levels (e.g. framebuffers)
8815    * then we ignore the passed value and we override it with
8816    * the stage implementation's preferred size.
8817    */
8818   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8819       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8820     return;
8821
8822   info = _clutter_actor_get_layout_info (self);
8823
8824   if (priv->min_width_set && min_width == info->min_width)
8825     return;
8826
8827   g_object_freeze_notify (G_OBJECT (self));
8828
8829   clutter_actor_store_old_geometry (self, &old);
8830
8831   info->min_width = min_width;
8832   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8833   clutter_actor_set_min_width_set (self, TRUE);
8834
8835   clutter_actor_notify_if_geometry_changed (self, &old);
8836
8837   g_object_thaw_notify (G_OBJECT (self));
8838
8839   clutter_actor_queue_relayout (self);
8840 }
8841
8842 static void
8843 clutter_actor_set_min_height (ClutterActor *self,
8844                               gfloat        min_height)
8845
8846 {
8847   ClutterActorPrivate *priv = self->priv;
8848   ClutterActorBox old = { 0, };
8849   ClutterLayoutInfo *info;
8850
8851   /* if we are setting the size on a top-level actor and the
8852    * backend only supports static top-levels (e.g. framebuffers)
8853    * then we ignore the passed value and we override it with
8854    * the stage implementation's preferred size.
8855    */
8856   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8857       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8858     return;
8859
8860   info = _clutter_actor_get_layout_info (self);
8861
8862   if (priv->min_height_set && min_height == info->min_height)
8863     return;
8864
8865   g_object_freeze_notify (G_OBJECT (self));
8866
8867   clutter_actor_store_old_geometry (self, &old);
8868
8869   info->min_height = min_height;
8870   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8871   clutter_actor_set_min_height_set (self, TRUE);
8872
8873   clutter_actor_notify_if_geometry_changed (self, &old);
8874
8875   g_object_thaw_notify (G_OBJECT (self));
8876
8877   clutter_actor_queue_relayout (self);
8878 }
8879
8880 static void
8881 clutter_actor_set_natural_width (ClutterActor *self,
8882                                  gfloat        natural_width)
8883 {
8884   ClutterActorPrivate *priv = self->priv;
8885   ClutterActorBox old = { 0, };
8886   ClutterLayoutInfo *info;
8887
8888   /* if we are setting the size on a top-level actor and the
8889    * backend only supports static top-levels (e.g. framebuffers)
8890    * then we ignore the passed value and we override it with
8891    * the stage implementation's preferred size.
8892    */
8893   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8894       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8895     return;
8896
8897   info = _clutter_actor_get_layout_info (self);
8898
8899   if (priv->natural_width_set && natural_width == info->natural_width)
8900     return;
8901
8902   g_object_freeze_notify (G_OBJECT (self));
8903
8904   clutter_actor_store_old_geometry (self, &old);
8905
8906   info->natural_width = natural_width;
8907   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8908   clutter_actor_set_natural_width_set (self, TRUE);
8909
8910   clutter_actor_notify_if_geometry_changed (self, &old);
8911
8912   g_object_thaw_notify (G_OBJECT (self));
8913
8914   clutter_actor_queue_relayout (self);
8915 }
8916
8917 static void
8918 clutter_actor_set_natural_height (ClutterActor *self,
8919                                   gfloat        natural_height)
8920 {
8921   ClutterActorPrivate *priv = self->priv;
8922   ClutterActorBox old = { 0, };
8923   ClutterLayoutInfo *info;
8924
8925   /* if we are setting the size on a top-level actor and the
8926    * backend only supports static top-levels (e.g. framebuffers)
8927    * then we ignore the passed value and we override it with
8928    * the stage implementation's preferred size.
8929    */
8930   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8931       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8932     return;
8933
8934   info = _clutter_actor_get_layout_info (self);
8935
8936   if (priv->natural_height_set && natural_height == info->natural_height)
8937     return;
8938
8939   g_object_freeze_notify (G_OBJECT (self));
8940
8941   clutter_actor_store_old_geometry (self, &old);
8942
8943   info->natural_height = natural_height;
8944   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8945   clutter_actor_set_natural_height_set (self, TRUE);
8946
8947   clutter_actor_notify_if_geometry_changed (self, &old);
8948
8949   g_object_thaw_notify (G_OBJECT (self));
8950
8951   clutter_actor_queue_relayout (self);
8952 }
8953
8954 static void
8955 clutter_actor_set_min_width_set (ClutterActor *self,
8956                                  gboolean      use_min_width)
8957 {
8958   ClutterActorPrivate *priv = self->priv;
8959   ClutterActorBox old = { 0, };
8960
8961   if (priv->min_width_set == (use_min_width != FALSE))
8962     return;
8963
8964   clutter_actor_store_old_geometry (self, &old);
8965
8966   priv->min_width_set = use_min_width != FALSE;
8967   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8968
8969   clutter_actor_notify_if_geometry_changed (self, &old);
8970
8971   clutter_actor_queue_relayout (self);
8972 }
8973
8974 static void
8975 clutter_actor_set_min_height_set (ClutterActor *self,
8976                                   gboolean      use_min_height)
8977 {
8978   ClutterActorPrivate *priv = self->priv;
8979   ClutterActorBox old = { 0, };
8980
8981   if (priv->min_height_set == (use_min_height != FALSE))
8982     return;
8983
8984   clutter_actor_store_old_geometry (self, &old);
8985
8986   priv->min_height_set = use_min_height != FALSE;
8987   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8988
8989   clutter_actor_notify_if_geometry_changed (self, &old);
8990
8991   clutter_actor_queue_relayout (self);
8992 }
8993
8994 static void
8995 clutter_actor_set_natural_width_set (ClutterActor *self,
8996                                      gboolean      use_natural_width)
8997 {
8998   ClutterActorPrivate *priv = self->priv;
8999   ClutterActorBox old = { 0, };
9000
9001   if (priv->natural_width_set == (use_natural_width != FALSE))
9002     return;
9003
9004   clutter_actor_store_old_geometry (self, &old);
9005
9006   priv->natural_width_set = use_natural_width != FALSE;
9007   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9008
9009   clutter_actor_notify_if_geometry_changed (self, &old);
9010
9011   clutter_actor_queue_relayout (self);
9012 }
9013
9014 static void
9015 clutter_actor_set_natural_height_set (ClutterActor *self,
9016                                       gboolean      use_natural_height)
9017 {
9018   ClutterActorPrivate *priv = self->priv;
9019   ClutterActorBox old = { 0, };
9020
9021   if (priv->natural_height_set == (use_natural_height != FALSE))
9022     return;
9023
9024   clutter_actor_store_old_geometry (self, &old);
9025
9026   priv->natural_height_set = use_natural_height != FALSE;
9027   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9028
9029   clutter_actor_notify_if_geometry_changed (self, &old);
9030
9031   clutter_actor_queue_relayout (self);
9032 }
9033
9034 /**
9035  * clutter_actor_set_request_mode:
9036  * @self: a #ClutterActor
9037  * @mode: the request mode
9038  *
9039  * Sets the geometry request mode of @self.
9040  *
9041  * The @mode determines the order for invoking
9042  * clutter_actor_get_preferred_width() and
9043  * clutter_actor_get_preferred_height()
9044  *
9045  * Since: 1.2
9046  */
9047 void
9048 clutter_actor_set_request_mode (ClutterActor       *self,
9049                                 ClutterRequestMode  mode)
9050 {
9051   ClutterActorPrivate *priv;
9052
9053   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9054
9055   priv = self->priv;
9056
9057   if (priv->request_mode == mode)
9058     return;
9059
9060   priv->request_mode = mode;
9061
9062   priv->needs_width_request = TRUE;
9063   priv->needs_height_request = TRUE;
9064
9065   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9066
9067   clutter_actor_queue_relayout (self);
9068 }
9069
9070 /**
9071  * clutter_actor_get_request_mode:
9072  * @self: a #ClutterActor
9073  *
9074  * Retrieves the geometry request mode of @self
9075  *
9076  * Return value: the request mode for the actor
9077  *
9078  * Since: 1.2
9079  */
9080 ClutterRequestMode
9081 clutter_actor_get_request_mode (ClutterActor *self)
9082 {
9083   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9084                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9085
9086   return self->priv->request_mode;
9087 }
9088
9089 /* variant of set_width() without checks and without notification
9090  * freeze+thaw, for internal usage only
9091  */
9092 static inline void
9093 clutter_actor_set_width_internal (ClutterActor *self,
9094                                   gfloat        width)
9095 {
9096   if (width >= 0)
9097     {
9098       /* the Stage will use the :min-width to control the minimum
9099        * width to be resized to, so we should not be setting it
9100        * along with the :natural-width
9101        */
9102       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9103         clutter_actor_set_min_width (self, width);
9104
9105       clutter_actor_set_natural_width (self, width);
9106     }
9107   else
9108     {
9109       /* we only unset the :natural-width for the Stage */
9110       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9111         clutter_actor_set_min_width_set (self, FALSE);
9112
9113       clutter_actor_set_natural_width_set (self, FALSE);
9114     }
9115 }
9116
9117 /* variant of set_height() without checks and without notification
9118  * freeze+thaw, for internal usage only
9119  */
9120 static inline void
9121 clutter_actor_set_height_internal (ClutterActor *self,
9122                                    gfloat        height)
9123 {
9124   if (height >= 0)
9125     {
9126       /* see the comment above in set_width_internal() */
9127       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9128         clutter_actor_set_min_height (self, height);
9129
9130       clutter_actor_set_natural_height (self, height);
9131     }
9132   else
9133     {
9134       /* see the comment above in set_width_internal() */
9135       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9136         clutter_actor_set_min_height_set (self, FALSE);
9137
9138       clutter_actor_set_natural_height_set (self, FALSE);
9139     }
9140 }
9141
9142 /**
9143  * clutter_actor_set_size:
9144  * @self: A #ClutterActor
9145  * @width: New width of actor in pixels, or -1
9146  * @height: New height of actor in pixels, or -1
9147  *
9148  * Sets the actor's size request in pixels. This overrides any
9149  * "normal" size request the actor would have. For example
9150  * a text actor might normally request the size of the text;
9151  * this function would force a specific size instead.
9152  *
9153  * If @width and/or @height are -1 the actor will use its
9154  * "normal" size request instead of overriding it, i.e.
9155  * you can "unset" the size with -1.
9156  *
9157  * This function sets or unsets both the minimum and natural size.
9158  */
9159 void
9160 clutter_actor_set_size (ClutterActor *self,
9161                         gfloat        width,
9162                         gfloat        height)
9163 {
9164   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9165
9166   g_object_freeze_notify (G_OBJECT (self));
9167
9168   clutter_actor_set_width (self, width);
9169   clutter_actor_set_height (self, height);
9170
9171   g_object_thaw_notify (G_OBJECT (self));
9172 }
9173
9174 /**
9175  * clutter_actor_get_size:
9176  * @self: A #ClutterActor
9177  * @width: (out) (allow-none): return location for the width, or %NULL.
9178  * @height: (out) (allow-none): return location for the height, or %NULL.
9179  *
9180  * This function tries to "do what you mean" and return
9181  * the size an actor will have. If the actor has a valid
9182  * allocation, the allocation will be returned; otherwise,
9183  * the actors natural size request will be returned.
9184  *
9185  * If you care whether you get the request vs. the allocation, you
9186  * should probably call a different function like
9187  * clutter_actor_get_allocation_box() or
9188  * clutter_actor_get_preferred_width().
9189  *
9190  * Since: 0.2
9191  */
9192 void
9193 clutter_actor_get_size (ClutterActor *self,
9194                         gfloat       *width,
9195                         gfloat       *height)
9196 {
9197   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9198
9199   if (width)
9200     *width = clutter_actor_get_width (self);
9201
9202   if (height)
9203     *height = clutter_actor_get_height (self);
9204 }
9205
9206 /**
9207  * clutter_actor_get_position:
9208  * @self: a #ClutterActor
9209  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9210  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9211  *
9212  * This function tries to "do what you mean" and tell you where the
9213  * actor is, prior to any transformations. Retrieves the fixed
9214  * position of an actor in pixels, if one has been set; otherwise, if
9215  * the allocation is valid, returns the actor's allocated position;
9216  * otherwise, returns 0,0.
9217  *
9218  * The returned position is in pixels.
9219  *
9220  * Since: 0.6
9221  */
9222 void
9223 clutter_actor_get_position (ClutterActor *self,
9224                             gfloat       *x,
9225                             gfloat       *y)
9226 {
9227   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9228
9229   if (x)
9230     *x = clutter_actor_get_x (self);
9231
9232   if (y)
9233     *y = clutter_actor_get_y (self);
9234 }
9235
9236 /**
9237  * clutter_actor_get_transformed_position:
9238  * @self: A #ClutterActor
9239  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9240  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9241  *
9242  * Gets the absolute position of an actor, in pixels relative to the stage.
9243  *
9244  * Since: 0.8
9245  */
9246 void
9247 clutter_actor_get_transformed_position (ClutterActor *self,
9248                                         gfloat       *x,
9249                                         gfloat       *y)
9250 {
9251   ClutterVertex v1;
9252   ClutterVertex v2;
9253
9254   v1.x = v1.y = v1.z = 0;
9255   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9256
9257   if (x)
9258     *x = v2.x;
9259
9260   if (y)
9261     *y = v2.y;
9262 }
9263
9264 /**
9265  * clutter_actor_get_transformed_size:
9266  * @self: A #ClutterActor
9267  * @width: (out) (allow-none): return location for the width, or %NULL
9268  * @height: (out) (allow-none): return location for the height, or %NULL
9269  *
9270  * Gets the absolute size of an actor in pixels, taking into account the
9271  * scaling factors.
9272  *
9273  * If the actor has a valid allocation, the allocated size will be used.
9274  * If the actor has not a valid allocation then the preferred size will
9275  * be transformed and returned.
9276  *
9277  * If you want the transformed allocation, see
9278  * clutter_actor_get_abs_allocation_vertices() instead.
9279  *
9280  * <note>When the actor (or one of its ancestors) is rotated around the
9281  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9282  * as a generic quadrangle; in that case this function returns the size
9283  * of the smallest rectangle that encapsulates the entire quad. Please
9284  * note that in this case no assumptions can be made about the relative
9285  * position of this envelope to the absolute position of the actor, as
9286  * returned by clutter_actor_get_transformed_position(); if you need this
9287  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9288  * to get the coords of the actual quadrangle.</note>
9289  *
9290  * Since: 0.8
9291  */
9292 void
9293 clutter_actor_get_transformed_size (ClutterActor *self,
9294                                     gfloat       *width,
9295                                     gfloat       *height)
9296 {
9297   ClutterActorPrivate *priv;
9298   ClutterVertex v[4];
9299   gfloat x_min, x_max, y_min, y_max;
9300   gint i;
9301
9302   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9303
9304   priv = self->priv;
9305
9306   /* if the actor hasn't been allocated yet, get the preferred
9307    * size and transform that
9308    */
9309   if (priv->needs_allocation)
9310     {
9311       gfloat natural_width, natural_height;
9312       ClutterActorBox box;
9313
9314       /* Make a fake allocation to transform.
9315        *
9316        * NB: _clutter_actor_transform_and_project_box expects a box in
9317        * the actor's coordinate space... */
9318
9319       box.x1 = 0;
9320       box.y1 = 0;
9321
9322       natural_width = natural_height = 0;
9323       clutter_actor_get_preferred_size (self, NULL, NULL,
9324                                         &natural_width,
9325                                         &natural_height);
9326
9327       box.x2 = natural_width;
9328       box.y2 = natural_height;
9329
9330       _clutter_actor_transform_and_project_box (self, &box, v);
9331     }
9332   else
9333     clutter_actor_get_abs_allocation_vertices (self, v);
9334
9335   x_min = x_max = v[0].x;
9336   y_min = y_max = v[0].y;
9337
9338   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9339     {
9340       if (v[i].x < x_min)
9341         x_min = v[i].x;
9342
9343       if (v[i].x > x_max)
9344         x_max = v[i].x;
9345
9346       if (v[i].y < y_min)
9347         y_min = v[i].y;
9348
9349       if (v[i].y > y_max)
9350         y_max = v[i].y;
9351     }
9352
9353   if (width)
9354     *width  = x_max - x_min;
9355
9356   if (height)
9357     *height = y_max - y_min;
9358 }
9359
9360 /**
9361  * clutter_actor_get_width:
9362  * @self: A #ClutterActor
9363  *
9364  * Retrieves the width of a #ClutterActor.
9365  *
9366  * If the actor has a valid allocation, this function will return the
9367  * width of the allocated area given to the actor.
9368  *
9369  * If the actor does not have a valid allocation, this function will
9370  * return the actor's natural width, that is the preferred width of
9371  * the actor.
9372  *
9373  * If you care whether you get the preferred width or the width that
9374  * has been assigned to the actor, you should probably call a different
9375  * function like clutter_actor_get_allocation_box() to retrieve the
9376  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9377  * preferred width.
9378  *
9379  * If an actor has a fixed width, for instance a width that has been
9380  * assigned using clutter_actor_set_width(), the width returned will
9381  * be the same value.
9382  *
9383  * Return value: the width of the actor, in pixels
9384  */
9385 gfloat
9386 clutter_actor_get_width (ClutterActor *self)
9387 {
9388   ClutterActorPrivate *priv;
9389
9390   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9391
9392   priv = self->priv;
9393
9394   if (priv->needs_allocation)
9395     {
9396       gfloat natural_width = 0;
9397
9398       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9399         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9400       else
9401         {
9402           gfloat natural_height = 0;
9403
9404           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9405           clutter_actor_get_preferred_width (self, natural_height,
9406                                              NULL,
9407                                              &natural_width);
9408         }
9409
9410       return natural_width;
9411     }
9412   else
9413     return priv->allocation.x2 - priv->allocation.x1;
9414 }
9415
9416 /**
9417  * clutter_actor_get_height:
9418  * @self: A #ClutterActor
9419  *
9420  * Retrieves the height of a #ClutterActor.
9421  *
9422  * If the actor has a valid allocation, this function will return the
9423  * height of the allocated area given to the actor.
9424  *
9425  * If the actor does not have a valid allocation, this function will
9426  * return the actor's natural height, that is the preferred height of
9427  * the actor.
9428  *
9429  * If you care whether you get the preferred height or the height that
9430  * has been assigned to the actor, you should probably call a different
9431  * function like clutter_actor_get_allocation_box() to retrieve the
9432  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9433  * preferred height.
9434  *
9435  * If an actor has a fixed height, for instance a height that has been
9436  * assigned using clutter_actor_set_height(), the height returned will
9437  * be the same value.
9438  *
9439  * Return value: the height of the actor, in pixels
9440  */
9441 gfloat
9442 clutter_actor_get_height (ClutterActor *self)
9443 {
9444   ClutterActorPrivate *priv;
9445
9446   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9447
9448   priv = self->priv;
9449
9450   if (priv->needs_allocation)
9451     {
9452       gfloat natural_height = 0;
9453
9454       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9455         {
9456           gfloat natural_width = 0;
9457
9458           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9459           clutter_actor_get_preferred_height (self, natural_width,
9460                                               NULL, &natural_height);
9461         }
9462       else
9463         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9464
9465       return natural_height;
9466     }
9467   else
9468     return priv->allocation.y2 - priv->allocation.y1;
9469 }
9470
9471 /**
9472  * clutter_actor_set_width:
9473  * @self: A #ClutterActor
9474  * @width: Requested new width for the actor, in pixels, or -1
9475  *
9476  * Forces a width on an actor, causing the actor's preferred width
9477  * and height (if any) to be ignored.
9478  *
9479  * If @width is -1 the actor will use its preferred width request
9480  * instead of overriding it, i.e. you can "unset" the width with -1.
9481  *
9482  * This function sets both the minimum and natural size of the actor.
9483  *
9484  * since: 0.2
9485  */
9486 void
9487 clutter_actor_set_width (ClutterActor *self,
9488                          gfloat        width)
9489 {
9490   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9491
9492   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9493     {
9494       float cur_size;
9495
9496       /* minor optimization: if we don't have a duration
9497        * then we can skip the get_width() below, to avoid
9498        * the chance of going through get_preferred_width()
9499        * just to jump to a new desired width.
9500        */
9501       if (clutter_actor_get_easing_duration (self) == 0)
9502         {
9503           g_object_freeze_notify (G_OBJECT (self));
9504
9505           clutter_actor_set_width_internal (self, width);
9506
9507           g_object_thaw_notify (G_OBJECT (self));
9508
9509           return;
9510         }
9511       else
9512         cur_size = clutter_actor_get_width (self);
9513
9514       _clutter_actor_create_transition (self,
9515                                         obj_props[PROP_WIDTH],
9516                                         cur_size,
9517                                         width);
9518     }
9519   else
9520     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9521 }
9522
9523 /**
9524  * clutter_actor_set_height:
9525  * @self: A #ClutterActor
9526  * @height: Requested new height for the actor, in pixels, or -1
9527  *
9528  * Forces a height on an actor, causing the actor's preferred width
9529  * and height (if any) to be ignored.
9530  *
9531  * If @height is -1 the actor will use its preferred height instead of
9532  * overriding it, i.e. you can "unset" the height with -1.
9533  *
9534  * This function sets both the minimum and natural size of the actor.
9535  *
9536  * since: 0.2
9537  */
9538 void
9539 clutter_actor_set_height (ClutterActor *self,
9540                           gfloat        height)
9541 {
9542   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9543
9544   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9545     {
9546       float cur_size;
9547
9548       /* see the comment in clutter_actor_set_width() above */
9549       if (clutter_actor_get_easing_duration (self) == 0)
9550         {
9551           g_object_freeze_notify (G_OBJECT (self));
9552
9553           clutter_actor_set_height_internal (self, height);
9554
9555           g_object_thaw_notify (G_OBJECT (self));
9556
9557           return;
9558         }
9559       else
9560         cur_size = clutter_actor_get_height (self);
9561
9562       _clutter_actor_create_transition (self,
9563                                         obj_props[PROP_HEIGHT],
9564                                         cur_size,
9565                                         height);
9566     }
9567   else
9568     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9569 }
9570
9571 static inline void
9572 clutter_actor_set_x_internal (ClutterActor *self,
9573                               float         x)
9574 {
9575   ClutterActorPrivate *priv = self->priv;
9576   ClutterLayoutInfo *linfo;
9577   ClutterActorBox old = { 0, };
9578
9579   linfo = _clutter_actor_get_layout_info (self);
9580
9581   if (priv->position_set && linfo->fixed_x == x)
9582     return;
9583
9584   clutter_actor_store_old_geometry (self, &old);
9585
9586   linfo->fixed_x = x;
9587   clutter_actor_set_fixed_position_set (self, TRUE);
9588
9589   clutter_actor_notify_if_geometry_changed (self, &old);
9590
9591   clutter_actor_queue_relayout (self);
9592 }
9593
9594 static inline void
9595 clutter_actor_set_y_internal (ClutterActor *self,
9596                               float         y)
9597 {
9598   ClutterActorPrivate *priv = self->priv;
9599   ClutterLayoutInfo *linfo;
9600   ClutterActorBox old = { 0, };
9601
9602   linfo = _clutter_actor_get_layout_info (self);
9603
9604   if (priv->position_set && linfo->fixed_y == y)
9605     return;
9606
9607   clutter_actor_store_old_geometry (self, &old);
9608
9609   linfo->fixed_y = y;
9610   clutter_actor_set_fixed_position_set (self, TRUE);
9611
9612   clutter_actor_notify_if_geometry_changed (self, &old);
9613
9614   clutter_actor_queue_relayout (self);
9615 }
9616
9617 /**
9618  * clutter_actor_set_x:
9619  * @self: a #ClutterActor
9620  * @x: the actor's position on the X axis
9621  *
9622  * Sets the actor's X coordinate, relative to its parent, in pixels.
9623  *
9624  * Overrides any layout manager and forces a fixed position for
9625  * the actor.
9626  *
9627  * The #ClutterActor:x property is animatable.
9628  *
9629  * Since: 0.6
9630  */
9631 void
9632 clutter_actor_set_x (ClutterActor *self,
9633                      gfloat        x)
9634 {
9635   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9636
9637   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9638     {
9639       float cur_position = clutter_actor_get_x (self);
9640
9641       _clutter_actor_create_transition (self, obj_props[PROP_X],
9642                                         cur_position,
9643                                         x);
9644     }
9645   else
9646     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9647 }
9648
9649 /**
9650  * clutter_actor_set_y:
9651  * @self: a #ClutterActor
9652  * @y: the actor's position on the Y axis
9653  *
9654  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9655  *
9656  * Overrides any layout manager and forces a fixed position for
9657  * the actor.
9658  *
9659  * The #ClutterActor:y property is animatable.
9660  *
9661  * Since: 0.6
9662  */
9663 void
9664 clutter_actor_set_y (ClutterActor *self,
9665                      gfloat        y)
9666 {
9667   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9668
9669   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9670     {
9671       float cur_position = clutter_actor_get_y (self);
9672
9673       _clutter_actor_create_transition (self, obj_props[PROP_Y],
9674                                         cur_position,
9675                                         y);
9676     }
9677   else
9678     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9679 }
9680
9681 /**
9682  * clutter_actor_get_x:
9683  * @self: A #ClutterActor
9684  *
9685  * Retrieves the X coordinate of a #ClutterActor.
9686  *
9687  * This function tries to "do what you mean", by returning the
9688  * correct value depending on the actor's state.
9689  *
9690  * If the actor has a valid allocation, this function will return
9691  * the X coordinate of the origin of the allocation box.
9692  *
9693  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9694  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9695  * function will return that coordinate.
9696  *
9697  * If both the allocation and a fixed position are missing, this function
9698  * will return 0.
9699  *
9700  * Return value: the X coordinate, in pixels, ignoring any
9701  *   transformation (i.e. scaling, rotation)
9702  */
9703 gfloat
9704 clutter_actor_get_x (ClutterActor *self)
9705 {
9706   ClutterActorPrivate *priv;
9707
9708   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9709
9710   priv = self->priv;
9711
9712   if (priv->needs_allocation)
9713     {
9714       if (priv->position_set)
9715         {
9716           const ClutterLayoutInfo *info;
9717
9718           info = _clutter_actor_get_layout_info_or_defaults (self);
9719
9720           return info->fixed_x;
9721         }
9722       else
9723         return 0;
9724     }
9725   else
9726     return priv->allocation.x1;
9727 }
9728
9729 /**
9730  * clutter_actor_get_y:
9731  * @self: A #ClutterActor
9732  *
9733  * Retrieves the Y coordinate of a #ClutterActor.
9734  *
9735  * This function tries to "do what you mean", by returning the
9736  * correct value depending on the actor's state.
9737  *
9738  * If the actor has a valid allocation, this function will return
9739  * the Y coordinate of the origin of the allocation box.
9740  *
9741  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9742  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9743  * function will return that coordinate.
9744  *
9745  * If both the allocation and a fixed position are missing, this function
9746  * will return 0.
9747  *
9748  * Return value: the Y coordinate, in pixels, ignoring any
9749  *   transformation (i.e. scaling, rotation)
9750  */
9751 gfloat
9752 clutter_actor_get_y (ClutterActor *self)
9753 {
9754   ClutterActorPrivate *priv;
9755
9756   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9757
9758   priv = self->priv;
9759
9760   if (priv->needs_allocation)
9761     {
9762       if (priv->position_set)
9763         {
9764           const ClutterLayoutInfo *info;
9765
9766           info = _clutter_actor_get_layout_info_or_defaults (self);
9767
9768           return info->fixed_y;
9769         }
9770       else
9771         return 0;
9772     }
9773   else
9774     return priv->allocation.y1;
9775 }
9776
9777 /**
9778  * clutter_actor_set_scale:
9779  * @self: A #ClutterActor
9780  * @scale_x: double factor to scale actor by horizontally.
9781  * @scale_y: double factor to scale actor by vertically.
9782  *
9783  * Scales an actor with the given factors. The scaling is relative to
9784  * the scale center and the anchor point. The scale center is
9785  * unchanged by this function and defaults to 0,0.
9786  *
9787  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9788  * animatable.
9789  *
9790  * Since: 0.2
9791  */
9792 void
9793 clutter_actor_set_scale (ClutterActor *self,
9794                          gdouble       scale_x,
9795                          gdouble       scale_y)
9796 {
9797   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9798
9799   g_object_freeze_notify (G_OBJECT (self));
9800
9801   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9802   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9803
9804   g_object_thaw_notify (G_OBJECT (self));
9805 }
9806
9807 /**
9808  * clutter_actor_set_scale_full:
9809  * @self: A #ClutterActor
9810  * @scale_x: double factor to scale actor by horizontally.
9811  * @scale_y: double factor to scale actor by vertically.
9812  * @center_x: X coordinate of the center of the scale.
9813  * @center_y: Y coordinate of the center of the scale
9814  *
9815  * Scales an actor with the given factors around the given center
9816  * point. The center point is specified in pixels relative to the
9817  * anchor point (usually the top left corner of the actor).
9818  *
9819  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9820  * are animatable.
9821  *
9822  * Since: 1.0
9823  */
9824 void
9825 clutter_actor_set_scale_full (ClutterActor *self,
9826                               gdouble       scale_x,
9827                               gdouble       scale_y,
9828                               gfloat        center_x,
9829                               gfloat        center_y)
9830 {
9831   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9832
9833   g_object_freeze_notify (G_OBJECT (self));
9834
9835   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9836   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9837   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9838   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9839
9840   g_object_thaw_notify (G_OBJECT (self));
9841 }
9842
9843 /**
9844  * clutter_actor_set_scale_with_gravity:
9845  * @self: A #ClutterActor
9846  * @scale_x: double factor to scale actor by horizontally.
9847  * @scale_y: double factor to scale actor by vertically.
9848  * @gravity: the location of the scale center expressed as a compass
9849  * direction.
9850  *
9851  * Scales an actor with the given factors around the given
9852  * center point. The center point is specified as one of the compass
9853  * directions in #ClutterGravity. For example, setting it to north
9854  * will cause the top of the actor to remain unchanged and the rest of
9855  * the actor to expand left, right and downwards.
9856  *
9857  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9858  * animatable.
9859  *
9860  * Since: 1.0
9861  */
9862 void
9863 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9864                                       gdouble         scale_x,
9865                                       gdouble         scale_y,
9866                                       ClutterGravity  gravity)
9867 {
9868   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9869
9870   g_object_freeze_notify (G_OBJECT (self));
9871
9872   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9873   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9874   clutter_actor_set_scale_gravity (self, gravity);
9875
9876   g_object_thaw_notify (G_OBJECT (self));
9877 }
9878
9879 /**
9880  * clutter_actor_get_scale:
9881  * @self: A #ClutterActor
9882  * @scale_x: (out) (allow-none): Location to store horizonal
9883  *   scale factor, or %NULL.
9884  * @scale_y: (out) (allow-none): Location to store vertical
9885  *   scale factor, or %NULL.
9886  *
9887  * Retrieves an actors scale factors.
9888  *
9889  * Since: 0.2
9890  */
9891 void
9892 clutter_actor_get_scale (ClutterActor *self,
9893                          gdouble      *scale_x,
9894                          gdouble      *scale_y)
9895 {
9896   const ClutterTransformInfo *info;
9897
9898   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9899
9900   info = _clutter_actor_get_transform_info_or_defaults (self);
9901
9902   if (scale_x)
9903     *scale_x = info->scale_x;
9904
9905   if (scale_y)
9906     *scale_y = info->scale_y;
9907 }
9908
9909 /**
9910  * clutter_actor_get_scale_center:
9911  * @self: A #ClutterActor
9912  * @center_x: (out) (allow-none): Location to store the X position
9913  *   of the scale center, or %NULL.
9914  * @center_y: (out) (allow-none): Location to store the Y position
9915  *   of the scale center, or %NULL.
9916  *
9917  * Retrieves the scale center coordinate in pixels relative to the top
9918  * left corner of the actor. If the scale center was specified using a
9919  * #ClutterGravity this will calculate the pixel offset using the
9920  * current size of the actor.
9921  *
9922  * Since: 1.0
9923  */
9924 void
9925 clutter_actor_get_scale_center (ClutterActor *self,
9926                                 gfloat       *center_x,
9927                                 gfloat       *center_y)
9928 {
9929   const ClutterTransformInfo *info;
9930
9931   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9932
9933   info = _clutter_actor_get_transform_info_or_defaults (self);
9934
9935   clutter_anchor_coord_get_units (self, &info->scale_center,
9936                                   center_x,
9937                                   center_y,
9938                                   NULL);
9939 }
9940
9941 /**
9942  * clutter_actor_get_scale_gravity:
9943  * @self: A #ClutterActor
9944  *
9945  * Retrieves the scale center as a compass direction. If the scale
9946  * center was specified in pixels or units this will return
9947  * %CLUTTER_GRAVITY_NONE.
9948  *
9949  * Return value: the scale gravity
9950  *
9951  * Since: 1.0
9952  */
9953 ClutterGravity
9954 clutter_actor_get_scale_gravity (ClutterActor *self)
9955 {
9956   const ClutterTransformInfo *info;
9957
9958   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9959
9960   info = _clutter_actor_get_transform_info_or_defaults (self);
9961
9962   return clutter_anchor_coord_get_gravity (&info->scale_center);
9963 }
9964
9965 static inline void
9966 clutter_actor_set_opacity_internal (ClutterActor *self,
9967                                     guint8        opacity)
9968 {
9969   ClutterActorPrivate *priv = self->priv;
9970
9971   if (priv->opacity != opacity)
9972     {
9973       priv->opacity = opacity;
9974
9975       /* Queue a redraw from the flatten effect so that it can use
9976          its cached image if available instead of having to redraw the
9977          actual actor. If it doesn't end up using the FBO then the
9978          effect is still able to continue the paint anyway. If there
9979          is no flatten effect yet then this is equivalent to queueing
9980          a full redraw */
9981       _clutter_actor_queue_redraw_full (self,
9982                                         0, /* flags */
9983                                         NULL, /* clip */
9984                                         priv->flatten_effect);
9985
9986       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9987     }
9988 }
9989
9990 /**
9991  * clutter_actor_set_opacity:
9992  * @self: A #ClutterActor
9993  * @opacity: New opacity value for the actor.
9994  *
9995  * Sets the actor's opacity, with zero being completely transparent and
9996  * 255 (0xff) being fully opaque.
9997  *
9998  * The #ClutterActor:opacity property is animatable.
9999  */
10000 void
10001 clutter_actor_set_opacity (ClutterActor *self,
10002                            guint8        opacity)
10003 {
10004   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10005
10006   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10007     {
10008       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10009                                         self->priv->opacity,
10010                                         opacity);
10011     }
10012   else
10013     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10014 }
10015
10016 /*
10017  * clutter_actor_get_paint_opacity_internal:
10018  * @self: a #ClutterActor
10019  *
10020  * Retrieves the absolute opacity of the actor, as it appears on the stage
10021  *
10022  * This function does not do type checks
10023  *
10024  * Return value: the absolute opacity of the actor
10025  */
10026 static guint8
10027 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10028 {
10029   ClutterActorPrivate *priv = self->priv;
10030   ClutterActor *parent;
10031
10032   /* override the top-level opacity to always be 255; even in
10033    * case of ClutterStage:use-alpha being TRUE we want the rest
10034    * of the scene to be painted
10035    */
10036   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10037     return 255;
10038
10039   if (priv->opacity_override >= 0)
10040     return priv->opacity_override;
10041
10042   parent = priv->parent;
10043
10044   /* Factor in the actual actors opacity with parents */
10045   if (parent != NULL)
10046     {
10047       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10048
10049       if (opacity != 0xff)
10050         return (opacity * priv->opacity) / 0xff;
10051     }
10052
10053   return priv->opacity;
10054
10055 }
10056
10057 /**
10058  * clutter_actor_get_paint_opacity:
10059  * @self: A #ClutterActor
10060  *
10061  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10062  *
10063  * This function traverses the hierarchy chain and composites the opacity of
10064  * the actor with that of its parents.
10065  *
10066  * This function is intended for subclasses to use in the paint virtual
10067  * function, to paint themselves with the correct opacity.
10068  *
10069  * Return value: The actor opacity value.
10070  *
10071  * Since: 0.8
10072  */
10073 guint8
10074 clutter_actor_get_paint_opacity (ClutterActor *self)
10075 {
10076   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10077
10078   return clutter_actor_get_paint_opacity_internal (self);
10079 }
10080
10081 /**
10082  * clutter_actor_get_opacity:
10083  * @self: a #ClutterActor
10084  *
10085  * Retrieves the opacity value of an actor, as set by
10086  * clutter_actor_set_opacity().
10087  *
10088  * For retrieving the absolute opacity of the actor inside a paint
10089  * virtual function, see clutter_actor_get_paint_opacity().
10090  *
10091  * Return value: the opacity of the actor
10092  */
10093 guint8
10094 clutter_actor_get_opacity (ClutterActor *self)
10095 {
10096   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10097
10098   return self->priv->opacity;
10099 }
10100
10101 /**
10102  * clutter_actor_set_offscreen_redirect:
10103  * @self: A #ClutterActor
10104  * @redirect: New offscreen redirect flags for the actor.
10105  *
10106  * Defines the circumstances where the actor should be redirected into
10107  * an offscreen image. The offscreen image is used to flatten the
10108  * actor into a single image while painting for two main reasons.
10109  * Firstly, when the actor is painted a second time without any of its
10110  * contents changing it can simply repaint the cached image without
10111  * descending further down the actor hierarchy. Secondly, it will make
10112  * the opacity look correct even if there are overlapping primitives
10113  * in the actor.
10114  *
10115  * Caching the actor could in some cases be a performance win and in
10116  * some cases be a performance lose so it is important to determine
10117  * which value is right for an actor before modifying this value. For
10118  * example, there is never any reason to flatten an actor that is just
10119  * a single texture (such as a #ClutterTexture) because it is
10120  * effectively already cached in an image so the offscreen would be
10121  * redundant. Also if the actor contains primitives that are far apart
10122  * with a large transparent area in the middle (such as a large
10123  * CluterGroup with a small actor in the top left and a small actor in
10124  * the bottom right) then the cached image will contain the entire
10125  * image of the large area and the paint will waste time blending all
10126  * of the transparent pixels in the middle.
10127  *
10128  * The default method of implementing opacity on a container simply
10129  * forwards on the opacity to all of the children. If the children are
10130  * overlapping then it will appear as if they are two separate glassy
10131  * objects and there will be a break in the color where they
10132  * overlap. By redirecting to an offscreen buffer it will be as if the
10133  * two opaque objects are combined into one and then made transparent
10134  * which is usually what is expected.
10135  *
10136  * The image below demonstrates the difference between redirecting and
10137  * not. The image shows two Clutter groups, each containing a red and
10138  * a green rectangle which overlap. The opacity on the group is set to
10139  * 128 (which is 50%). When the offscreen redirect is not used, the
10140  * red rectangle can be seen through the blue rectangle as if the two
10141  * rectangles were separately transparent. When the redirect is used
10142  * the group as a whole is transparent instead so the red rectangle is
10143  * not visible where they overlap.
10144  *
10145  * <figure id="offscreen-redirect">
10146  *   <title>Sample of using an offscreen redirect for transparency</title>
10147  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10148  * </figure>
10149  *
10150  * The default value for this property is 0, so we effectively will
10151  * never redirect an actor offscreen by default. This means that there
10152  * are times that transparent actors may look glassy as described
10153  * above. The reason this is the default is because there is a
10154  * performance trade off between quality and performance here. In many
10155  * cases the default form of glassy opacity looks good enough, but if
10156  * it's not you will need to set the
10157  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10158  * redirection for opacity.
10159  *
10160  * Custom actors that don't contain any overlapping primitives are
10161  * recommended to override the has_overlaps() virtual to return %FALSE
10162  * for maximum efficiency.
10163  *
10164  * Since: 1.8
10165  */
10166 void
10167 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10168                                       ClutterOffscreenRedirect redirect)
10169 {
10170   ClutterActorPrivate *priv;
10171
10172   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10173
10174   priv = self->priv;
10175
10176   if (priv->offscreen_redirect != redirect)
10177     {
10178       priv->offscreen_redirect = redirect;
10179
10180       /* Queue a redraw from the effect so that it can use its cached
10181          image if available instead of having to redraw the actual
10182          actor. If it doesn't end up using the FBO then the effect is
10183          still able to continue the paint anyway. If there is no
10184          effect then this is equivalent to queuing a full redraw */
10185       _clutter_actor_queue_redraw_full (self,
10186                                         0, /* flags */
10187                                         NULL, /* clip */
10188                                         priv->flatten_effect);
10189
10190       g_object_notify_by_pspec (G_OBJECT (self),
10191                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10192     }
10193 }
10194
10195 /**
10196  * clutter_actor_get_offscreen_redirect:
10197  * @self: a #ClutterActor
10198  *
10199  * Retrieves whether to redirect the actor to an offscreen buffer, as
10200  * set by clutter_actor_set_offscreen_redirect().
10201  *
10202  * Return value: the value of the offscreen-redirect property of the actor
10203  *
10204  * Since: 1.8
10205  */
10206 ClutterOffscreenRedirect
10207 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10208 {
10209   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10210
10211   return self->priv->offscreen_redirect;
10212 }
10213
10214 /**
10215  * clutter_actor_set_name:
10216  * @self: A #ClutterActor
10217  * @name: Textual tag to apply to actor
10218  *
10219  * Sets the given name to @self. The name can be used to identify
10220  * a #ClutterActor.
10221  */
10222 void
10223 clutter_actor_set_name (ClutterActor *self,
10224                         const gchar  *name)
10225 {
10226   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10227
10228   g_free (self->priv->name);
10229   self->priv->name = g_strdup (name);
10230
10231   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10232 }
10233
10234 /**
10235  * clutter_actor_get_name:
10236  * @self: A #ClutterActor
10237  *
10238  * Retrieves the name of @self.
10239  *
10240  * Return value: the name of the actor, or %NULL. The returned string is
10241  *   owned by the actor and should not be modified or freed.
10242  */
10243 const gchar *
10244 clutter_actor_get_name (ClutterActor *self)
10245 {
10246   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10247
10248   return self->priv->name;
10249 }
10250
10251 /**
10252  * clutter_actor_get_gid:
10253  * @self: A #ClutterActor
10254  *
10255  * Retrieves the unique id for @self.
10256  *
10257  * Return value: Globally unique value for this object instance.
10258  *
10259  * Since: 0.6
10260  *
10261  * Deprecated: 1.8: The id is not used any longer.
10262  */
10263 guint32
10264 clutter_actor_get_gid (ClutterActor *self)
10265 {
10266   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10267
10268   return self->priv->id;
10269 }
10270
10271 static inline void
10272 clutter_actor_set_depth_internal (ClutterActor *self,
10273                                   float         depth)
10274 {
10275   ClutterTransformInfo *info;
10276
10277   info = _clutter_actor_get_transform_info (self);
10278
10279   if (info->depth != depth)
10280     {
10281       /* Sets Z value - XXX 2.0: should we invert? */
10282       info->depth = depth;
10283
10284       self->priv->transform_valid = FALSE;
10285
10286       /* FIXME - remove this crap; sadly, there are still containers
10287        * in Clutter that depend on this utter brain damage
10288        */
10289       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10290
10291       clutter_actor_queue_redraw (self);
10292
10293       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10294     }
10295 }
10296
10297 /**
10298  * clutter_actor_set_depth:
10299  * @self: a #ClutterActor
10300  * @depth: Z co-ord
10301  *
10302  * Sets the Z coordinate of @self to @depth.
10303  *
10304  * The unit used by @depth is dependant on the perspective setup. See
10305  * also clutter_stage_set_perspective().
10306  */
10307 void
10308 clutter_actor_set_depth (ClutterActor *self,
10309                          gfloat        depth)
10310 {
10311   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10312
10313   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10314     {
10315       const ClutterTransformInfo *info;
10316
10317       info = _clutter_actor_get_transform_info_or_defaults (self);
10318
10319       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10320                                         info->depth,
10321                                         depth);
10322     }
10323   else
10324     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10325
10326   clutter_actor_queue_redraw (self);
10327 }
10328
10329 /**
10330  * clutter_actor_get_depth:
10331  * @self: a #ClutterActor
10332  *
10333  * Retrieves the depth of @self.
10334  *
10335  * Return value: the depth of the actor
10336  */
10337 gfloat
10338 clutter_actor_get_depth (ClutterActor *self)
10339 {
10340   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10341
10342   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10343 }
10344
10345 /**
10346  * clutter_actor_set_rotation:
10347  * @self: a #ClutterActor
10348  * @axis: the axis of rotation
10349  * @angle: the angle of rotation
10350  * @x: X coordinate of the rotation center
10351  * @y: Y coordinate of the rotation center
10352  * @z: Z coordinate of the rotation center
10353  *
10354  * Sets the rotation angle of @self around the given axis.
10355  *
10356  * The rotation center coordinates used depend on the value of @axis:
10357  * <itemizedlist>
10358  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10359  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10360  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10361  * </itemizedlist>
10362  *
10363  * The rotation coordinates are relative to the anchor point of the
10364  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10365  * point is set, the upper left corner is assumed as the origin.
10366  *
10367  * Since: 0.8
10368  */
10369 void
10370 clutter_actor_set_rotation (ClutterActor      *self,
10371                             ClutterRotateAxis  axis,
10372                             gdouble            angle,
10373                             gfloat             x,
10374                             gfloat             y,
10375                             gfloat             z)
10376 {
10377   ClutterVertex v;
10378
10379   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10380
10381   v.x = x;
10382   v.y = y;
10383   v.z = z;
10384
10385   g_object_freeze_notify (G_OBJECT (self));
10386
10387   clutter_actor_set_rotation_angle (self, axis, angle);
10388   clutter_actor_set_rotation_center_internal (self, axis, &v);
10389
10390   g_object_thaw_notify (G_OBJECT (self));
10391 }
10392
10393 /**
10394  * clutter_actor_set_z_rotation_from_gravity:
10395  * @self: a #ClutterActor
10396  * @angle: the angle of rotation
10397  * @gravity: the center point of the rotation
10398  *
10399  * Sets the rotation angle of @self around the Z axis using the center
10400  * point specified as a compass point. For example to rotate such that
10401  * the center of the actor remains static you can use
10402  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10403  * will move accordingly.
10404  *
10405  * Since: 1.0
10406  */
10407 void
10408 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10409                                            gdouble         angle,
10410                                            ClutterGravity  gravity)
10411 {
10412   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10413
10414   if (gravity == CLUTTER_GRAVITY_NONE)
10415     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10416   else
10417     {
10418       GObject *obj = G_OBJECT (self);
10419       ClutterTransformInfo *info;
10420
10421       info = _clutter_actor_get_transform_info (self);
10422
10423       g_object_freeze_notify (obj);
10424
10425       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10426
10427       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10428       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10429       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10430
10431       g_object_thaw_notify (obj);
10432     }
10433 }
10434
10435 /**
10436  * clutter_actor_get_rotation:
10437  * @self: a #ClutterActor
10438  * @axis: the axis of rotation
10439  * @x: (out): return value for the X coordinate of the center of rotation
10440  * @y: (out): return value for the Y coordinate of the center of rotation
10441  * @z: (out): return value for the Z coordinate of the center of rotation
10442  *
10443  * Retrieves the angle and center of rotation on the given axis,
10444  * set using clutter_actor_set_rotation().
10445  *
10446  * Return value: the angle of rotation
10447  *
10448  * Since: 0.8
10449  */
10450 gdouble
10451 clutter_actor_get_rotation (ClutterActor      *self,
10452                             ClutterRotateAxis  axis,
10453                             gfloat            *x,
10454                             gfloat            *y,
10455                             gfloat            *z)
10456 {
10457   const ClutterTransformInfo *info;
10458   const AnchorCoord *anchor_coord;
10459   gdouble retval = 0;
10460
10461   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10462
10463   info = _clutter_actor_get_transform_info_or_defaults (self);
10464
10465   switch (axis)
10466     {
10467     case CLUTTER_X_AXIS:
10468       anchor_coord = &info->rx_center;
10469       retval = info->rx_angle;
10470       break;
10471
10472     case CLUTTER_Y_AXIS:
10473       anchor_coord = &info->ry_center;
10474       retval = info->ry_angle;
10475       break;
10476
10477     case CLUTTER_Z_AXIS:
10478       anchor_coord = &info->rz_center;
10479       retval = info->rz_angle;
10480       break;
10481
10482     default:
10483       anchor_coord = NULL;
10484       retval = 0.0;
10485       break;
10486     }
10487
10488   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10489
10490   return retval;
10491 }
10492
10493 /**
10494  * clutter_actor_get_z_rotation_gravity:
10495  * @self: A #ClutterActor
10496  *
10497  * Retrieves the center for the rotation around the Z axis as a
10498  * compass direction. If the center was specified in pixels or units
10499  * this will return %CLUTTER_GRAVITY_NONE.
10500  *
10501  * Return value: the Z rotation center
10502  *
10503  * Since: 1.0
10504  */
10505 ClutterGravity
10506 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10507 {
10508   const ClutterTransformInfo *info;
10509
10510   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10511
10512   info = _clutter_actor_get_transform_info_or_defaults (self);
10513
10514   return clutter_anchor_coord_get_gravity (&info->rz_center);
10515 }
10516
10517 /**
10518  * clutter_actor_set_clip:
10519  * @self: A #ClutterActor
10520  * @xoff: X offset of the clip rectangle
10521  * @yoff: Y offset of the clip rectangle
10522  * @width: Width of the clip rectangle
10523  * @height: Height of the clip rectangle
10524  *
10525  * Sets clip area for @self. The clip area is always computed from the
10526  * upper left corner of the actor, even if the anchor point is set
10527  * otherwise.
10528  *
10529  * Since: 0.6
10530  */
10531 void
10532 clutter_actor_set_clip (ClutterActor *self,
10533                         gfloat        xoff,
10534                         gfloat        yoff,
10535                         gfloat        width,
10536                         gfloat        height)
10537 {
10538   ClutterActorPrivate *priv;
10539
10540   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10541
10542   priv = self->priv;
10543
10544   if (priv->has_clip &&
10545       priv->clip.x == xoff &&
10546       priv->clip.y == yoff &&
10547       priv->clip.width == width &&
10548       priv->clip.height == height)
10549     return;
10550
10551   priv->clip.x = xoff;
10552   priv->clip.y = yoff;
10553   priv->clip.width = width;
10554   priv->clip.height = height;
10555
10556   priv->has_clip = TRUE;
10557
10558   clutter_actor_queue_redraw (self);
10559
10560   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10561   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10562 }
10563
10564 /**
10565  * clutter_actor_remove_clip:
10566  * @self: A #ClutterActor
10567  *
10568  * Removes clip area from @self.
10569  */
10570 void
10571 clutter_actor_remove_clip (ClutterActor *self)
10572 {
10573   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10574
10575   if (!self->priv->has_clip)
10576     return;
10577
10578   self->priv->has_clip = FALSE;
10579
10580   clutter_actor_queue_redraw (self);
10581
10582   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10583 }
10584
10585 /**
10586  * clutter_actor_has_clip:
10587  * @self: a #ClutterActor
10588  *
10589  * Determines whether the actor has a clip area set or not.
10590  *
10591  * Return value: %TRUE if the actor has a clip area set.
10592  *
10593  * Since: 0.1.1
10594  */
10595 gboolean
10596 clutter_actor_has_clip (ClutterActor *self)
10597 {
10598   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10599
10600   return self->priv->has_clip;
10601 }
10602
10603 /**
10604  * clutter_actor_get_clip:
10605  * @self: a #ClutterActor
10606  * @xoff: (out) (allow-none): return location for the X offset of
10607  *   the clip rectangle, or %NULL
10608  * @yoff: (out) (allow-none): return location for the Y offset of
10609  *   the clip rectangle, or %NULL
10610  * @width: (out) (allow-none): return location for the width of
10611  *   the clip rectangle, or %NULL
10612  * @height: (out) (allow-none): return location for the height of
10613  *   the clip rectangle, or %NULL
10614  *
10615  * Gets the clip area for @self, if any is set
10616  *
10617  * Since: 0.6
10618  */
10619 void
10620 clutter_actor_get_clip (ClutterActor *self,
10621                         gfloat       *xoff,
10622                         gfloat       *yoff,
10623                         gfloat       *width,
10624                         gfloat       *height)
10625 {
10626   ClutterActorPrivate *priv;
10627
10628   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10629
10630   priv = self->priv;
10631
10632   if (!priv->has_clip)
10633     return;
10634
10635   if (xoff != NULL)
10636     *xoff = priv->clip.x;
10637
10638   if (yoff != NULL)
10639     *yoff = priv->clip.y;
10640
10641   if (width != NULL)
10642     *width = priv->clip.width;
10643
10644   if (height != NULL)
10645     *height = priv->clip.height;
10646 }
10647
10648 /**
10649  * clutter_actor_get_children:
10650  * @self: a #ClutterActor
10651  *
10652  * Retrieves the list of children of @self.
10653  *
10654  * Return value: (transfer container) (element-type ClutterActor): A newly
10655  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10656  *   done.
10657  *
10658  * Since: 1.10
10659  */
10660 GList *
10661 clutter_actor_get_children (ClutterActor *self)
10662 {
10663   ClutterActor *iter;
10664   GList *res;
10665
10666   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10667
10668   /* we walk the list backward so that we can use prepend(),
10669    * which is O(1)
10670    */
10671   for (iter = self->priv->last_child, res = NULL;
10672        iter != NULL;
10673        iter = iter->priv->prev_sibling)
10674     {
10675       res = g_list_prepend (res, iter);
10676     }
10677
10678   return res;
10679 }
10680
10681 /*< private >
10682  * insert_child_at_depth:
10683  * @self: a #ClutterActor
10684  * @child: a #ClutterActor
10685  *
10686  * Inserts @child inside the list of children held by @self, using
10687  * the depth as the insertion criteria.
10688  *
10689  * This sadly makes the insertion not O(1), but we can keep the
10690  * list sorted so that the painters algorithm we use for painting
10691  * the children will work correctly.
10692  */
10693 static void
10694 insert_child_at_depth (ClutterActor *self,
10695                        ClutterActor *child,
10696                        gpointer      dummy G_GNUC_UNUSED)
10697 {
10698   ClutterActor *iter;
10699   float child_depth;
10700
10701   child->priv->parent = self;
10702
10703   child_depth =
10704     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10705
10706   /* special-case the first child */
10707   if (self->priv->n_children == 0)
10708     {
10709       self->priv->first_child = child;
10710       self->priv->last_child = child;
10711
10712       child->priv->next_sibling = NULL;
10713       child->priv->prev_sibling = NULL;
10714
10715       return;
10716     }
10717
10718   /* Find the right place to insert the child so that it will still be
10719      sorted and the child will be after all of the actors at the same
10720      dept */
10721   for (iter = self->priv->first_child;
10722        iter != NULL;
10723        iter = iter->priv->next_sibling)
10724     {
10725       float iter_depth;
10726
10727       iter_depth =
10728         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10729
10730       if (iter_depth > child_depth)
10731         break;
10732     }
10733
10734   if (iter != NULL)
10735     {
10736       ClutterActor *tmp = iter->priv->prev_sibling;
10737
10738       if (tmp != NULL)
10739         tmp->priv->next_sibling = child;
10740
10741       /* Insert the node before the found one */
10742       child->priv->prev_sibling = iter->priv->prev_sibling;
10743       child->priv->next_sibling = iter;
10744       iter->priv->prev_sibling = child;
10745     }
10746   else
10747     {
10748       ClutterActor *tmp = self->priv->last_child;
10749
10750       if (tmp != NULL)
10751         tmp->priv->next_sibling = child;
10752
10753       /* insert the node at the end of the list */
10754       child->priv->prev_sibling = self->priv->last_child;
10755       child->priv->next_sibling = NULL;
10756     }
10757
10758   if (child->priv->prev_sibling == NULL)
10759     self->priv->first_child = child;
10760
10761   if (child->priv->next_sibling == NULL)
10762     self->priv->last_child = child;
10763 }
10764
10765 static void
10766 insert_child_at_index (ClutterActor *self,
10767                        ClutterActor *child,
10768                        gpointer      data_)
10769 {
10770   gint index_ = GPOINTER_TO_INT (data_);
10771
10772   child->priv->parent = self;
10773
10774   if (index_ == 0)
10775     {
10776       ClutterActor *tmp = self->priv->first_child;
10777
10778       if (tmp != NULL)
10779         tmp->priv->prev_sibling = child;
10780
10781       child->priv->prev_sibling = NULL;
10782       child->priv->next_sibling = tmp;
10783     }
10784   else if (index_ < 0 || index_ >= self->priv->n_children)
10785     {
10786       ClutterActor *tmp = self->priv->last_child;
10787
10788       if (tmp != NULL)
10789         tmp->priv->next_sibling = child;
10790
10791       child->priv->prev_sibling = tmp;
10792       child->priv->next_sibling = NULL;
10793     }
10794   else
10795     {
10796       ClutterActor *iter;
10797       int i;
10798
10799       for (iter = self->priv->first_child, i = 0;
10800            iter != NULL;
10801            iter = iter->priv->next_sibling, i += 1)
10802         {
10803           if (index_ == i)
10804             {
10805               ClutterActor *tmp = iter->priv->prev_sibling;
10806
10807               child->priv->prev_sibling = tmp;
10808               child->priv->next_sibling = iter;
10809
10810               iter->priv->prev_sibling = child;
10811
10812               if (tmp != NULL)
10813                 tmp->priv->next_sibling = child;
10814
10815               break;
10816             }
10817         }
10818     }
10819
10820   if (child->priv->prev_sibling == NULL)
10821     self->priv->first_child = child;
10822
10823   if (child->priv->next_sibling == NULL)
10824     self->priv->last_child = child;
10825 }
10826
10827 static void
10828 insert_child_above (ClutterActor *self,
10829                     ClutterActor *child,
10830                     gpointer      data)
10831 {
10832   ClutterActor *sibling = data;
10833
10834   child->priv->parent = self;
10835
10836   if (sibling == NULL)
10837     sibling = self->priv->last_child;
10838
10839   child->priv->prev_sibling = sibling;
10840
10841   if (sibling != NULL)
10842     {
10843       ClutterActor *tmp = sibling->priv->next_sibling;
10844
10845       child->priv->next_sibling = tmp;
10846
10847       if (tmp != NULL)
10848         tmp->priv->prev_sibling = child;
10849
10850       sibling->priv->next_sibling = child;
10851     }
10852   else
10853     child->priv->next_sibling = NULL;
10854
10855   if (child->priv->prev_sibling == NULL)
10856     self->priv->first_child = child;
10857
10858   if (child->priv->next_sibling == NULL)
10859     self->priv->last_child = child;
10860 }
10861
10862 static void
10863 insert_child_below (ClutterActor *self,
10864                     ClutterActor *child,
10865                     gpointer      data)
10866 {
10867   ClutterActor *sibling = data;
10868
10869   child->priv->parent = self;
10870
10871   if (sibling == NULL)
10872     sibling = self->priv->first_child;
10873
10874   child->priv->next_sibling = sibling;
10875
10876   if (sibling != NULL)
10877     {
10878       ClutterActor *tmp = sibling->priv->prev_sibling;
10879
10880       child->priv->prev_sibling = tmp;
10881
10882       if (tmp != NULL)
10883         tmp->priv->next_sibling = child;
10884
10885       sibling->priv->prev_sibling = child;
10886     }
10887   else
10888     child->priv->prev_sibling = NULL;
10889
10890   if (child->priv->prev_sibling == NULL)
10891     self->priv->first_child = child;
10892
10893   if (child->priv->next_sibling == NULL)
10894     self->priv->last_child = child;
10895 }
10896
10897 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10898                                            ClutterActor *child,
10899                                            gpointer      data);
10900
10901 typedef enum {
10902   ADD_CHILD_CREATE_META       = 1 << 0,
10903   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10904   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10905   ADD_CHILD_CHECK_STATE       = 1 << 3,
10906   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10907
10908   /* default flags for public API */
10909   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10910                                ADD_CHILD_EMIT_PARENT_SET |
10911                                ADD_CHILD_EMIT_ACTOR_ADDED |
10912                                ADD_CHILD_CHECK_STATE |
10913                                ADD_CHILD_NOTIFY_FIRST_LAST,
10914
10915   /* flags for legacy/deprecated API */
10916   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10917                                ADD_CHILD_CHECK_STATE |
10918                                ADD_CHILD_NOTIFY_FIRST_LAST
10919 } ClutterActorAddChildFlags;
10920
10921 /*< private >
10922  * clutter_actor_add_child_internal:
10923  * @self: a #ClutterActor
10924  * @child: a #ClutterActor
10925  * @flags: control flags for actions
10926  * @add_func: delegate function
10927  * @data: (closure): data to pass to @add_func
10928  *
10929  * Adds @child to the list of children of @self.
10930  *
10931  * The actual insertion inside the list is delegated to @add_func: this
10932  * function will just set up the state, perform basic checks, and emit
10933  * signals.
10934  *
10935  * The @flags argument is used to perform additional operations.
10936  */
10937 static inline void
10938 clutter_actor_add_child_internal (ClutterActor              *self,
10939                                   ClutterActor              *child,
10940                                   ClutterActorAddChildFlags  flags,
10941                                   ClutterActorAddChildFunc   add_func,
10942                                   gpointer                   data)
10943 {
10944   ClutterTextDirection text_dir;
10945   gboolean create_meta;
10946   gboolean emit_parent_set, emit_actor_added;
10947   gboolean check_state;
10948   gboolean notify_first_last;
10949   ClutterActor *old_first_child, *old_last_child;
10950
10951   if (child->priv->parent != NULL)
10952     {
10953       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10954                  "use clutter_actor_remove_child() first.",
10955                  _clutter_actor_get_debug_name (child),
10956                  _clutter_actor_get_debug_name (child->priv->parent));
10957       return;
10958     }
10959
10960   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10961     {
10962       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10963                  "a child of another actor.",
10964                  _clutter_actor_get_debug_name (child));
10965       return;
10966     }
10967
10968 #if 0
10969   /* XXX - this check disallows calling methods that change the stacking
10970    * order within the destruction sequence, by triggering a critical
10971    * warning first, and leaving the actor in an undefined state, which
10972    * then ends up being caught by an assertion.
10973    *
10974    * the reproducible sequence is:
10975    *
10976    *   - actor gets destroyed;
10977    *   - another actor, linked to the first, will try to change the
10978    *     stacking order of the first actor;
10979    *   - changing the stacking order is a composite operation composed
10980    *     by the following steps:
10981    *     1. ref() the child;
10982    *     2. remove_child_internal(), which removes the reference;
10983    *     3. add_child_internal(), which adds a reference;
10984    *   - the state of the actor is not changed between (2) and (3), as
10985    *     it could be an expensive recomputation;
10986    *   - if (3) bails out, then the actor is in an undefined state, but
10987    *     still alive;
10988    *   - the destruction sequence terminates, but the actor is unparented
10989    *     while its state indicates being parented instead.
10990    *   - assertion failure.
10991    *
10992    * the obvious fix would be to decompose each set_child_*_sibling()
10993    * method into proper remove_child()/add_child(), with state validation;
10994    * this may cause excessive work, though, and trigger a cascade of other
10995    * bugs in code that assumes that a change in the stacking order is an
10996    * atomic operation.
10997    *
10998    * another potential fix is to just remove this check here, and let
10999    * code doing stacking order changes inside the destruction sequence
11000    * of an actor continue doing the work.
11001    *
11002    * the third fix is to silently bail out early from every
11003    * set_child_*_sibling() and set_child_at_index() method, and avoid
11004    * doing work.
11005    *
11006    * I have a preference for the second solution, since it involves the
11007    * least amount of work, and the least amount of code duplication.
11008    *
11009    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11010    */
11011   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11012     {
11013       g_warning ("The actor '%s' is currently being destroyed, and "
11014                  "cannot be added as a child of another actor.",
11015                  _clutter_actor_get_debug_name (child));
11016       return;
11017     }
11018 #endif
11019
11020   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11021   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11022   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11023   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11024   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11025
11026   old_first_child = self->priv->first_child;
11027   old_last_child = self->priv->last_child;
11028
11029   g_object_freeze_notify (G_OBJECT (self));
11030
11031   if (create_meta)
11032     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11033
11034   g_object_ref_sink (child);
11035   child->priv->parent = NULL;
11036   child->priv->next_sibling = NULL;
11037   child->priv->prev_sibling = NULL;
11038
11039   /* delegate the actual insertion */
11040   add_func (self, child, data);
11041
11042   g_assert (child->priv->parent == self);
11043
11044   self->priv->n_children += 1;
11045
11046   self->priv->age += 1;
11047
11048   /* if push_internal() has been called then we automatically set
11049    * the flag on the actor
11050    */
11051   if (self->priv->internal_child)
11052     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11053
11054   /* clutter_actor_reparent() will emit ::parent-set for us */
11055   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11056     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11057
11058   if (check_state)
11059     {
11060       /* If parent is mapped or realized, we need to also be mapped or
11061        * realized once we're inside the parent.
11062        */
11063       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11064
11065       /* propagate the parent's text direction to the child */
11066       text_dir = clutter_actor_get_text_direction (self);
11067       clutter_actor_set_text_direction (child, text_dir);
11068     }
11069
11070   if (child->priv->show_on_set_parent)
11071     clutter_actor_show (child);
11072
11073   if (CLUTTER_ACTOR_IS_MAPPED (child))
11074     clutter_actor_queue_redraw (child);
11075
11076   /* maintain the invariant that if an actor needs layout,
11077    * its parents do as well
11078    */
11079   if (child->priv->needs_width_request ||
11080       child->priv->needs_height_request ||
11081       child->priv->needs_allocation)
11082     {
11083       /* we work around the short-circuiting we do
11084        * in clutter_actor_queue_relayout() since we
11085        * want to force a relayout
11086        */
11087       child->priv->needs_width_request = TRUE;
11088       child->priv->needs_height_request = TRUE;
11089       child->priv->needs_allocation = TRUE;
11090
11091       clutter_actor_queue_relayout (child->priv->parent);
11092     }
11093
11094   if (emit_actor_added)
11095     g_signal_emit_by_name (self, "actor-added", child);
11096
11097   if (notify_first_last)
11098     {
11099       if (old_first_child != self->priv->first_child)
11100         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11101
11102       if (old_last_child != self->priv->last_child)
11103         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11104     }
11105
11106   g_object_thaw_notify (G_OBJECT (self));
11107 }
11108
11109 /**
11110  * clutter_actor_add_child:
11111  * @self: a #ClutterActor
11112  * @child: a #ClutterActor
11113  *
11114  * Adds @child to the children of @self.
11115  *
11116  * This function will acquire a reference on @child that will only
11117  * be released when calling clutter_actor_remove_child().
11118  *
11119  * This function will take into consideration the #ClutterActor:depth
11120  * of @child, and will keep the list of children sorted.
11121  *
11122  * This function will emit the #ClutterContainer::actor-added signal
11123  * on @self.
11124  *
11125  * Since: 1.10
11126  */
11127 void
11128 clutter_actor_add_child (ClutterActor *self,
11129                          ClutterActor *child)
11130 {
11131   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11132   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11133   g_return_if_fail (self != child);
11134   g_return_if_fail (child->priv->parent == NULL);
11135
11136   clutter_actor_add_child_internal (self, child,
11137                                     ADD_CHILD_DEFAULT_FLAGS,
11138                                     insert_child_at_depth,
11139                                     NULL);
11140 }
11141
11142 /**
11143  * clutter_actor_insert_child_at_index:
11144  * @self: a #ClutterActor
11145  * @child: a #ClutterActor
11146  * @index_: the index
11147  *
11148  * Inserts @child into the list of children of @self, using the
11149  * given @index_. If @index_ is greater than the number of children
11150  * in @self, or is less than 0, then the new child is added at the end.
11151  *
11152  * This function will acquire a reference on @child that will only
11153  * be released when calling clutter_actor_remove_child().
11154  *
11155  * This function will not take into consideration the #ClutterActor:depth
11156  * of @child.
11157  *
11158  * This function will emit the #ClutterContainer::actor-added signal
11159  * on @self.
11160  *
11161  * Since: 1.10
11162  */
11163 void
11164 clutter_actor_insert_child_at_index (ClutterActor *self,
11165                                      ClutterActor *child,
11166                                      gint          index_)
11167 {
11168   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11169   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11170   g_return_if_fail (self != child);
11171   g_return_if_fail (child->priv->parent == NULL);
11172
11173   clutter_actor_add_child_internal (self, child,
11174                                     ADD_CHILD_DEFAULT_FLAGS,
11175                                     insert_child_at_index,
11176                                     GINT_TO_POINTER (index_));
11177 }
11178
11179 /**
11180  * clutter_actor_insert_child_above:
11181  * @self: a #ClutterActor
11182  * @child: a #ClutterActor
11183  * @sibling: (allow-none): a child of @self, or %NULL
11184  *
11185  * Inserts @child into the list of children of @self, above another
11186  * child of @self or, if @sibling is %NULL, above all the children
11187  * of @self.
11188  *
11189  * This function will acquire a reference on @child that will only
11190  * be released when calling clutter_actor_remove_child().
11191  *
11192  * This function will not take into consideration the #ClutterActor:depth
11193  * of @child.
11194  *
11195  * This function will emit the #ClutterContainer::actor-added signal
11196  * on @self.
11197  *
11198  * Since: 1.10
11199  */
11200 void
11201 clutter_actor_insert_child_above (ClutterActor *self,
11202                                   ClutterActor *child,
11203                                   ClutterActor *sibling)
11204 {
11205   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11206   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11207   g_return_if_fail (self != child);
11208   g_return_if_fail (child != sibling);
11209   g_return_if_fail (child->priv->parent == NULL);
11210   g_return_if_fail (sibling == NULL ||
11211                     (CLUTTER_IS_ACTOR (sibling) &&
11212                      sibling->priv->parent == self));
11213
11214   clutter_actor_add_child_internal (self, child,
11215                                     ADD_CHILD_DEFAULT_FLAGS,
11216                                     insert_child_above,
11217                                     sibling);
11218 }
11219
11220 /**
11221  * clutter_actor_insert_child_below:
11222  * @self: a #ClutterActor
11223  * @child: a #ClutterActor
11224  * @sibling: (allow-none): a child of @self, or %NULL
11225  *
11226  * Inserts @child into the list of children of @self, below another
11227  * child of @self or, if @sibling is %NULL, below all the children
11228  * of @self.
11229  *
11230  * This function will acquire a reference on @child that will only
11231  * be released when calling clutter_actor_remove_child().
11232  *
11233  * This function will not take into consideration the #ClutterActor:depth
11234  * of @child.
11235  *
11236  * This function will emit the #ClutterContainer::actor-added signal
11237  * on @self.
11238  *
11239  * Since: 1.10
11240  */
11241 void
11242 clutter_actor_insert_child_below (ClutterActor *self,
11243                                   ClutterActor *child,
11244                                   ClutterActor *sibling)
11245 {
11246   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11247   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11248   g_return_if_fail (self != child);
11249   g_return_if_fail (child != sibling);
11250   g_return_if_fail (child->priv->parent == NULL);
11251   g_return_if_fail (sibling == NULL ||
11252                     (CLUTTER_IS_ACTOR (sibling) &&
11253                      sibling->priv->parent == self));
11254
11255   clutter_actor_add_child_internal (self, child,
11256                                     ADD_CHILD_DEFAULT_FLAGS,
11257                                     insert_child_below,
11258                                     sibling);
11259 }
11260
11261 /**
11262  * clutter_actor_set_parent:
11263  * @self: A #ClutterActor
11264  * @parent: A new #ClutterActor parent
11265  *
11266  * Sets the parent of @self to @parent.
11267  *
11268  * This function will result in @parent acquiring a reference on @self,
11269  * eventually by sinking its floating reference first. The reference
11270  * will be released by clutter_actor_unparent().
11271  *
11272  * This function should only be called by legacy #ClutterActor<!-- -->s
11273  * implementing the #ClutterContainer interface.
11274  *
11275  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11276  */
11277 void
11278 clutter_actor_set_parent (ClutterActor *self,
11279                           ClutterActor *parent)
11280 {
11281   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11282   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11283   g_return_if_fail (self != parent);
11284   g_return_if_fail (self->priv->parent == NULL);
11285
11286   /* as this function will be called inside ClutterContainer::add
11287    * implementations or when building up a composite actor, we have
11288    * to preserve the old behaviour, and not create child meta or
11289    * emit the ::actor-added signal, to avoid recursion or double
11290    * emissions
11291    */
11292   clutter_actor_add_child_internal (parent, self,
11293                                     ADD_CHILD_LEGACY_FLAGS,
11294                                     insert_child_at_depth,
11295                                     NULL);
11296 }
11297
11298 /**
11299  * clutter_actor_get_parent:
11300  * @self: A #ClutterActor
11301  *
11302  * Retrieves the parent of @self.
11303  *
11304  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11305  *  if no parent is set
11306  */
11307 ClutterActor *
11308 clutter_actor_get_parent (ClutterActor *self)
11309 {
11310   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11311
11312   return self->priv->parent;
11313 }
11314
11315 /**
11316  * clutter_actor_get_paint_visibility:
11317  * @self: A #ClutterActor
11318  *
11319  * Retrieves the 'paint' visibility of an actor recursively checking for non
11320  * visible parents.
11321  *
11322  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11323  *
11324  * Return Value: %TRUE if the actor is visibile and will be painted.
11325  *
11326  * Since: 0.8.4
11327  */
11328 gboolean
11329 clutter_actor_get_paint_visibility (ClutterActor *actor)
11330 {
11331   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11332
11333   return CLUTTER_ACTOR_IS_MAPPED (actor);
11334 }
11335
11336 /**
11337  * clutter_actor_remove_child:
11338  * @self: a #ClutterActor
11339  * @child: a #ClutterActor
11340  *
11341  * Removes @child from the children of @self.
11342  *
11343  * This function will release the reference added by
11344  * clutter_actor_add_child(), so if you want to keep using @child
11345  * you will have to acquire a referenced on it before calling this
11346  * function.
11347  *
11348  * This function will emit the #ClutterContainer::actor-removed
11349  * signal on @self.
11350  *
11351  * Since: 1.10
11352  */
11353 void
11354 clutter_actor_remove_child (ClutterActor *self,
11355                             ClutterActor *child)
11356 {
11357   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11358   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11359   g_return_if_fail (self != child);
11360   g_return_if_fail (child->priv->parent != NULL);
11361   g_return_if_fail (child->priv->parent == self);
11362
11363   clutter_actor_remove_child_internal (self, child,
11364                                        REMOVE_CHILD_DEFAULT_FLAGS);
11365 }
11366
11367 /**
11368  * clutter_actor_remove_all_children:
11369  * @self: a #ClutterActor
11370  *
11371  * Removes all children of @self.
11372  *
11373  * This function releases the reference added by inserting a child actor
11374  * in the list of children of @self.
11375  *
11376  * If the reference count of a child drops to zero, the child will be
11377  * destroyed. If you want to ensure the destruction of all the children
11378  * of @self, use clutter_actor_destroy_all_children().
11379  *
11380  * Since: 1.10
11381  */
11382 void
11383 clutter_actor_remove_all_children (ClutterActor *self)
11384 {
11385   ClutterActorIter iter;
11386
11387   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11388
11389   if (self->priv->n_children == 0)
11390     return;
11391
11392   g_object_freeze_notify (G_OBJECT (self));
11393
11394   clutter_actor_iter_init (&iter, self);
11395   while (clutter_actor_iter_next (&iter, NULL))
11396     clutter_actor_iter_remove (&iter);
11397
11398   g_object_thaw_notify (G_OBJECT (self));
11399
11400   /* sanity check */
11401   g_assert (self->priv->first_child == NULL);
11402   g_assert (self->priv->last_child == NULL);
11403   g_assert (self->priv->n_children == 0);
11404 }
11405
11406 /**
11407  * clutter_actor_destroy_all_children:
11408  * @self: a #ClutterActor
11409  *
11410  * Destroys all children of @self.
11411  *
11412  * This function releases the reference added by inserting a child
11413  * actor in the list of children of @self, and ensures that the
11414  * #ClutterActor::destroy signal is emitted on each child of the
11415  * actor.
11416  *
11417  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11418  * when its reference count drops to 0; the default handler of the
11419  * #ClutterActor::destroy signal will destroy all the children of an
11420  * actor. This function ensures that all children are destroyed, instead
11421  * of just removed from @self, unlike clutter_actor_remove_all_children()
11422  * which will merely release the reference and remove each child.
11423  *
11424  * Unless you acquired an additional reference on each child of @self
11425  * prior to calling clutter_actor_remove_all_children() and want to reuse
11426  * the actors, you should use clutter_actor_destroy_all_children() in
11427  * order to make sure that children are destroyed and signal handlers
11428  * are disconnected even in cases where circular references prevent this
11429  * from automatically happening through reference counting alone.
11430  *
11431  * Since: 1.10
11432  */
11433 void
11434 clutter_actor_destroy_all_children (ClutterActor *self)
11435 {
11436   ClutterActorIter iter;
11437
11438   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11439
11440   if (self->priv->n_children == 0)
11441     return;
11442
11443   g_object_freeze_notify (G_OBJECT (self));
11444
11445   clutter_actor_iter_init (&iter, self);
11446   while (clutter_actor_iter_next (&iter, NULL))
11447     clutter_actor_iter_destroy (&iter);
11448
11449   g_object_thaw_notify (G_OBJECT (self));
11450
11451   /* sanity check */
11452   g_assert (self->priv->first_child == NULL);
11453   g_assert (self->priv->last_child == NULL);
11454   g_assert (self->priv->n_children == 0);
11455 }
11456
11457 typedef struct _InsertBetweenData {
11458   ClutterActor *prev_sibling;
11459   ClutterActor *next_sibling;
11460 } InsertBetweenData;
11461
11462 static void
11463 insert_child_between (ClutterActor *self,
11464                       ClutterActor *child,
11465                       gpointer      data_)
11466 {
11467   InsertBetweenData *data = data_;
11468   ClutterActor *prev_sibling = data->prev_sibling;
11469   ClutterActor *next_sibling = data->next_sibling;
11470
11471   child->priv->parent = self;
11472   child->priv->prev_sibling = prev_sibling;
11473   child->priv->next_sibling = next_sibling;
11474
11475   if (prev_sibling != NULL)
11476     prev_sibling->priv->next_sibling = child;
11477
11478   if (next_sibling != NULL)
11479     next_sibling->priv->prev_sibling = child;
11480
11481   if (child->priv->prev_sibling == NULL)
11482     self->priv->first_child = child;
11483
11484   if (child->priv->next_sibling == NULL)
11485     self->priv->last_child = child;
11486 }
11487
11488 /**
11489  * clutter_actor_replace_child:
11490  * @self: a #ClutterActor
11491  * @old_child: the child of @self to replace
11492  * @new_child: the #ClutterActor to replace @old_child
11493  *
11494  * Replaces @old_child with @new_child in the list of children of @self.
11495  *
11496  * Since: 1.10
11497  */
11498 void
11499 clutter_actor_replace_child (ClutterActor *self,
11500                              ClutterActor *old_child,
11501                              ClutterActor *new_child)
11502 {
11503   ClutterActor *prev_sibling, *next_sibling;
11504   InsertBetweenData clos;
11505
11506   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11507   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11508   g_return_if_fail (old_child->priv->parent == self);
11509   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11510   g_return_if_fail (old_child != new_child);
11511   g_return_if_fail (new_child != self);
11512   g_return_if_fail (new_child->priv->parent == NULL);
11513
11514   prev_sibling = old_child->priv->prev_sibling;
11515   next_sibling = old_child->priv->next_sibling;
11516   clutter_actor_remove_child_internal (self, old_child,
11517                                        REMOVE_CHILD_DEFAULT_FLAGS);
11518
11519   clos.prev_sibling = prev_sibling;
11520   clos.next_sibling = next_sibling;
11521   clutter_actor_add_child_internal (self, new_child,
11522                                     ADD_CHILD_DEFAULT_FLAGS,
11523                                     insert_child_between,
11524                                     &clos);
11525 }
11526
11527 /**
11528  * clutter_actor_unparent:
11529  * @self: a #ClutterActor
11530  *
11531  * Removes the parent of @self.
11532  *
11533  * This will cause the parent of @self to release the reference
11534  * acquired when calling clutter_actor_set_parent(), so if you
11535  * want to keep @self you will have to acquire a reference of
11536  * your own, through g_object_ref().
11537  *
11538  * This function should only be called by legacy #ClutterActor<!-- -->s
11539  * implementing the #ClutterContainer interface.
11540  *
11541  * Since: 0.1.1
11542  *
11543  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11544  */
11545 void
11546 clutter_actor_unparent (ClutterActor *self)
11547 {
11548   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11549
11550   if (self->priv->parent == NULL)
11551     return;
11552
11553   clutter_actor_remove_child_internal (self->priv->parent, self,
11554                                        REMOVE_CHILD_LEGACY_FLAGS);
11555 }
11556
11557 /**
11558  * clutter_actor_reparent:
11559  * @self: a #ClutterActor
11560  * @new_parent: the new #ClutterActor parent
11561  *
11562  * Resets the parent actor of @self.
11563  *
11564  * This function is logically equivalent to calling clutter_actor_unparent()
11565  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11566  * ensures the child is not finalized when unparented, and emits the
11567  * #ClutterActor::parent-set signal only once.
11568  *
11569  * In reality, calling this function is less useful than it sounds, as some
11570  * application code may rely on changes in the intermediate state between
11571  * removal and addition of the actor from its old parent to the @new_parent.
11572  * Thus, it is strongly encouraged to avoid using this function in application
11573  * code.
11574  *
11575  * Since: 0.2
11576  *
11577  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11578  *   clutter_actor_add_child() instead; remember to take a reference on
11579  *   the actor being removed before calling clutter_actor_remove_child()
11580  *   to avoid the reference count dropping to zero and the actor being
11581  *   destroyed.
11582  */
11583 void
11584 clutter_actor_reparent (ClutterActor *self,
11585                         ClutterActor *new_parent)
11586 {
11587   ClutterActorPrivate *priv;
11588
11589   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11590   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11591   g_return_if_fail (self != new_parent);
11592
11593   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11594     {
11595       g_warning ("Cannot set a parent on a toplevel actor");
11596       return;
11597     }
11598
11599   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11600     {
11601       g_warning ("Cannot set a parent currently being destroyed");
11602       return;
11603     }
11604
11605   priv = self->priv;
11606
11607   if (priv->parent != new_parent)
11608     {
11609       ClutterActor *old_parent;
11610
11611       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11612
11613       old_parent = priv->parent;
11614
11615       g_object_ref (self);
11616
11617       if (old_parent != NULL)
11618         {
11619          /* go through the Container implementation if this is a regular
11620           * child and not an internal one
11621           */
11622          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11623            {
11624              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11625
11626              /* this will have to call unparent() */
11627              clutter_container_remove_actor (parent, self);
11628            }
11629          else
11630            clutter_actor_remove_child_internal (old_parent, self,
11631                                                 REMOVE_CHILD_LEGACY_FLAGS);
11632         }
11633
11634       /* Note, will call set_parent() */
11635       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11636         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11637       else
11638         clutter_actor_add_child_internal (new_parent, self,
11639                                           ADD_CHILD_LEGACY_FLAGS,
11640                                           insert_child_at_depth,
11641                                           NULL);
11642
11643       /* we emit the ::parent-set signal once */
11644       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11645
11646       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11647
11648       /* the IN_REPARENT flag suspends state updates */
11649       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11650
11651       g_object_unref (self);
11652    }
11653 }
11654
11655 /**
11656  * clutter_actor_contains:
11657  * @self: A #ClutterActor
11658  * @descendant: A #ClutterActor, possibly contained in @self
11659  *
11660  * Determines if @descendant is contained inside @self (either as an
11661  * immediate child, or as a deeper descendant). If @self and
11662  * @descendant point to the same actor then it will also return %TRUE.
11663  *
11664  * Return value: whether @descendent is contained within @self
11665  *
11666  * Since: 1.4
11667  */
11668 gboolean
11669 clutter_actor_contains (ClutterActor *self,
11670                         ClutterActor *descendant)
11671 {
11672   ClutterActor *actor;
11673
11674   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11675   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11676
11677   for (actor = descendant; actor; actor = actor->priv->parent)
11678     if (actor == self)
11679       return TRUE;
11680
11681   return FALSE;
11682 }
11683
11684 /**
11685  * clutter_actor_set_child_above_sibling:
11686  * @self: a #ClutterActor
11687  * @child: a #ClutterActor child of @self
11688  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11689  *
11690  * Sets @child to be above @sibling in the list of children of @self.
11691  *
11692  * If @sibling is %NULL, @child will be the new last child of @self.
11693  *
11694  * This function is logically equivalent to removing @child and using
11695  * clutter_actor_insert_child_above(), but it will not emit signals
11696  * or change state on @child.
11697  *
11698  * Since: 1.10
11699  */
11700 void
11701 clutter_actor_set_child_above_sibling (ClutterActor *self,
11702                                        ClutterActor *child,
11703                                        ClutterActor *sibling)
11704 {
11705   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11706   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11707   g_return_if_fail (child->priv->parent == self);
11708   g_return_if_fail (child != sibling);
11709   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11710
11711   if (sibling != NULL)
11712     g_return_if_fail (sibling->priv->parent == self);
11713
11714   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11715       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11716       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11717     return;
11718
11719   /* we don't want to change the state of child, or emit signals, or
11720    * regenerate ChildMeta instances here, but we still want to follow
11721    * the correct sequence of steps encoded in remove_child() and
11722    * add_child(), so that correctness is ensured, and we only go
11723    * through one known code path.
11724    */
11725   g_object_ref (child);
11726   clutter_actor_remove_child_internal (self, child, 0);
11727   clutter_actor_add_child_internal (self, child,
11728                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11729                                     insert_child_above,
11730                                     sibling);
11731
11732   clutter_actor_queue_relayout (self);
11733 }
11734
11735 /**
11736  * clutter_actor_set_child_below_sibling:
11737  * @self: a #ClutterActor
11738  * @child: a #ClutterActor child of @self
11739  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11740  *
11741  * Sets @child to be below @sibling in the list of children of @self.
11742  *
11743  * If @sibling is %NULL, @child will be the new first child of @self.
11744  *
11745  * This function is logically equivalent to removing @self and using
11746  * clutter_actor_insert_child_below(), but it will not emit signals
11747  * or change state on @child.
11748  *
11749  * Since: 1.10
11750  */
11751 void
11752 clutter_actor_set_child_below_sibling (ClutterActor *self,
11753                                        ClutterActor *child,
11754                                        ClutterActor *sibling)
11755 {
11756   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11757   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11758   g_return_if_fail (child->priv->parent == self);
11759   g_return_if_fail (child != sibling);
11760   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11761
11762   if (sibling != NULL)
11763     g_return_if_fail (sibling->priv->parent == self);
11764
11765   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11766       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11767       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11768     return;
11769
11770   /* see the comment in set_child_above_sibling() */
11771   g_object_ref (child);
11772   clutter_actor_remove_child_internal (self, child, 0);
11773   clutter_actor_add_child_internal (self, child,
11774                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11775                                     insert_child_below,
11776                                     sibling);
11777
11778   clutter_actor_queue_relayout (self);
11779 }
11780
11781 /**
11782  * clutter_actor_set_child_at_index:
11783  * @self: a #ClutterActor
11784  * @child: a #ClutterActor child of @self
11785  * @index_: the new index for @child
11786  *
11787  * Changes the index of @child in the list of children of @self.
11788  *
11789  * This function is logically equivalent to removing @child and
11790  * calling clutter_actor_insert_child_at_index(), but it will not
11791  * emit signals or change state on @child.
11792  *
11793  * Since: 1.10
11794  */
11795 void
11796 clutter_actor_set_child_at_index (ClutterActor *self,
11797                                   ClutterActor *child,
11798                                   gint          index_)
11799 {
11800   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11801   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11802   g_return_if_fail (child->priv->parent == self);
11803   g_return_if_fail (index_ <= self->priv->n_children);
11804
11805   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11806       CLUTTER_ACTOR_IN_DESTRUCTION (child))
11807     return;
11808
11809   g_object_ref (child);
11810   clutter_actor_remove_child_internal (self, child, 0);
11811   clutter_actor_add_child_internal (self, child,
11812                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11813                                     insert_child_at_index,
11814                                     GINT_TO_POINTER (index_));
11815
11816   clutter_actor_queue_relayout (self);
11817 }
11818
11819 /**
11820  * clutter_actor_raise:
11821  * @self: A #ClutterActor
11822  * @below: (allow-none): A #ClutterActor to raise above.
11823  *
11824  * Puts @self above @below.
11825  *
11826  * Both actors must have the same parent, and the parent must implement
11827  * the #ClutterContainer interface
11828  *
11829  * This function calls clutter_container_raise_child() internally.
11830  *
11831  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11832  */
11833 void
11834 clutter_actor_raise (ClutterActor *self,
11835                      ClutterActor *below)
11836 {
11837   ClutterActor *parent;
11838
11839   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11840
11841   parent = clutter_actor_get_parent (self);
11842   if (parent == NULL)
11843     {
11844       g_warning ("%s: Actor '%s' is not inside a container",
11845                  G_STRFUNC,
11846                  _clutter_actor_get_debug_name (self));
11847       return;
11848     }
11849
11850   if (below != NULL)
11851     {
11852       if (parent != clutter_actor_get_parent (below))
11853         {
11854           g_warning ("%s Actor '%s' is not in the same container as "
11855                      "actor '%s'",
11856                      G_STRFUNC,
11857                      _clutter_actor_get_debug_name (self),
11858                      _clutter_actor_get_debug_name (below));
11859           return;
11860         }
11861     }
11862
11863   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11864 }
11865
11866 /**
11867  * clutter_actor_lower:
11868  * @self: A #ClutterActor
11869  * @above: (allow-none): A #ClutterActor to lower below
11870  *
11871  * Puts @self below @above.
11872  *
11873  * Both actors must have the same parent, and the parent must implement
11874  * the #ClutterContainer interface.
11875  *
11876  * This function calls clutter_container_lower_child() internally.
11877  *
11878  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11879  */
11880 void
11881 clutter_actor_lower (ClutterActor *self,
11882                      ClutterActor *above)
11883 {
11884   ClutterActor *parent;
11885
11886   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11887
11888   parent = clutter_actor_get_parent (self);
11889   if (parent == NULL)
11890     {
11891       g_warning ("%s: Actor of type %s is not inside a container",
11892                  G_STRFUNC,
11893                  _clutter_actor_get_debug_name (self));
11894       return;
11895     }
11896
11897   if (above)
11898     {
11899       if (parent != clutter_actor_get_parent (above))
11900         {
11901           g_warning ("%s: Actor '%s' is not in the same container as "
11902                      "actor '%s'",
11903                      G_STRFUNC,
11904                      _clutter_actor_get_debug_name (self),
11905                      _clutter_actor_get_debug_name (above));
11906           return;
11907         }
11908     }
11909
11910   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11911 }
11912
11913 /**
11914  * clutter_actor_raise_top:
11915  * @self: A #ClutterActor
11916  *
11917  * Raises @self to the top.
11918  *
11919  * This function calls clutter_actor_raise() internally.
11920  *
11921  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11922  *   a %NULL sibling, instead.
11923  */
11924 void
11925 clutter_actor_raise_top (ClutterActor *self)
11926 {
11927   clutter_actor_raise (self, NULL);
11928 }
11929
11930 /**
11931  * clutter_actor_lower_bottom:
11932  * @self: A #ClutterActor
11933  *
11934  * Lowers @self to the bottom.
11935  *
11936  * This function calls clutter_actor_lower() internally.
11937  *
11938  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11939  *   a %NULL sibling, instead.
11940  */
11941 void
11942 clutter_actor_lower_bottom (ClutterActor *self)
11943 {
11944   clutter_actor_lower (self, NULL);
11945 }
11946
11947 /*
11948  * Event handling
11949  */
11950
11951 /**
11952  * clutter_actor_event:
11953  * @actor: a #ClutterActor
11954  * @event: a #ClutterEvent
11955  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11956  *
11957  * This function is used to emit an event on the main stage.
11958  * You should rarely need to use this function, except for
11959  * synthetising events.
11960  *
11961  * Return value: the return value from the signal emission: %TRUE
11962  *   if the actor handled the event, or %FALSE if the event was
11963  *   not handled
11964  *
11965  * Since: 0.6
11966  */
11967 gboolean
11968 clutter_actor_event (ClutterActor *actor,
11969                      ClutterEvent *event,
11970                      gboolean      capture)
11971 {
11972   gboolean retval = FALSE;
11973   gint signal_num = -1;
11974
11975   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11976   g_return_val_if_fail (event != NULL, FALSE);
11977
11978   g_object_ref (actor);
11979
11980   if (capture)
11981     {
11982       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11983                      event,
11984                      &retval);
11985       goto out;
11986     }
11987
11988   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11989
11990   if (!retval)
11991     {
11992       switch (event->type)
11993         {
11994         case CLUTTER_NOTHING:
11995           break;
11996         case CLUTTER_BUTTON_PRESS:
11997           signal_num = BUTTON_PRESS_EVENT;
11998           break;
11999         case CLUTTER_BUTTON_RELEASE:
12000           signal_num = BUTTON_RELEASE_EVENT;
12001           break;
12002         case CLUTTER_SCROLL:
12003           signal_num = SCROLL_EVENT;
12004           break;
12005         case CLUTTER_KEY_PRESS:
12006           signal_num = KEY_PRESS_EVENT;
12007           break;
12008         case CLUTTER_KEY_RELEASE:
12009           signal_num = KEY_RELEASE_EVENT;
12010           break;
12011         case CLUTTER_MOTION:
12012           signal_num = MOTION_EVENT;
12013           break;
12014         case CLUTTER_ENTER:
12015           signal_num = ENTER_EVENT;
12016           break;
12017         case CLUTTER_LEAVE:
12018           signal_num = LEAVE_EVENT;
12019           break;
12020         case CLUTTER_DELETE:
12021         case CLUTTER_DESTROY_NOTIFY:
12022         case CLUTTER_CLIENT_MESSAGE:
12023         default:
12024           signal_num = -1;
12025           break;
12026         }
12027
12028       if (signal_num != -1)
12029         g_signal_emit (actor, actor_signals[signal_num], 0,
12030                        event, &retval);
12031     }
12032
12033 out:
12034   g_object_unref (actor);
12035
12036   return retval;
12037 }
12038
12039 /**
12040  * clutter_actor_set_reactive:
12041  * @actor: a #ClutterActor
12042  * @reactive: whether the actor should be reactive to events
12043  *
12044  * Sets @actor as reactive. Reactive actors will receive events.
12045  *
12046  * Since: 0.6
12047  */
12048 void
12049 clutter_actor_set_reactive (ClutterActor *actor,
12050                             gboolean      reactive)
12051 {
12052   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12053
12054   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12055     return;
12056
12057   if (reactive)
12058     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12059   else
12060     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12061
12062   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12063 }
12064
12065 /**
12066  * clutter_actor_get_reactive:
12067  * @actor: a #ClutterActor
12068  *
12069  * Checks whether @actor is marked as reactive.
12070  *
12071  * Return value: %TRUE if the actor is reactive
12072  *
12073  * Since: 0.6
12074  */
12075 gboolean
12076 clutter_actor_get_reactive (ClutterActor *actor)
12077 {
12078   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12079
12080   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12081 }
12082
12083 /**
12084  * clutter_actor_get_anchor_point:
12085  * @self: a #ClutterActor
12086  * @anchor_x: (out): return location for the X coordinate of the anchor point
12087  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12088  *
12089  * Gets the current anchor point of the @actor in pixels.
12090  *
12091  * Since: 0.6
12092  */
12093 void
12094 clutter_actor_get_anchor_point (ClutterActor *self,
12095                                 gfloat       *anchor_x,
12096                                 gfloat       *anchor_y)
12097 {
12098   const ClutterTransformInfo *info;
12099
12100   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12101
12102   info = _clutter_actor_get_transform_info_or_defaults (self);
12103   clutter_anchor_coord_get_units (self, &info->anchor,
12104                                   anchor_x,
12105                                   anchor_y,
12106                                   NULL);
12107 }
12108
12109 /**
12110  * clutter_actor_set_anchor_point:
12111  * @self: a #ClutterActor
12112  * @anchor_x: X coordinate of the anchor point
12113  * @anchor_y: Y coordinate of the anchor point
12114  *
12115  * Sets an anchor point for @self. The anchor point is a point in the
12116  * coordinate space of an actor to which the actor position within its
12117  * parent is relative; the default is (0, 0), i.e. the top-left corner
12118  * of the actor.
12119  *
12120  * Since: 0.6
12121  */
12122 void
12123 clutter_actor_set_anchor_point (ClutterActor *self,
12124                                 gfloat        anchor_x,
12125                                 gfloat        anchor_y)
12126 {
12127   ClutterTransformInfo *info;
12128   ClutterActorPrivate *priv;
12129   gboolean changed = FALSE;
12130   gfloat old_anchor_x, old_anchor_y;
12131   GObject *obj;
12132
12133   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12134
12135   obj = G_OBJECT (self);
12136   priv = self->priv;
12137   info = _clutter_actor_get_transform_info (self);
12138
12139   g_object_freeze_notify (obj);
12140
12141   clutter_anchor_coord_get_units (self, &info->anchor,
12142                                   &old_anchor_x,
12143                                   &old_anchor_y,
12144                                   NULL);
12145
12146   if (info->anchor.is_fractional)
12147     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12148
12149   if (old_anchor_x != anchor_x)
12150     {
12151       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12152       changed = TRUE;
12153     }
12154
12155   if (old_anchor_y != anchor_y)
12156     {
12157       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12158       changed = TRUE;
12159     }
12160
12161   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12162
12163   if (changed)
12164     {
12165       priv->transform_valid = FALSE;
12166       clutter_actor_queue_redraw (self);
12167     }
12168
12169   g_object_thaw_notify (obj);
12170 }
12171
12172 /**
12173  * clutter_actor_get_anchor_point_gravity:
12174  * @self: a #ClutterActor
12175  *
12176  * Retrieves the anchor position expressed as a #ClutterGravity. If
12177  * the anchor point was specified using pixels or units this will
12178  * return %CLUTTER_GRAVITY_NONE.
12179  *
12180  * Return value: the #ClutterGravity used by the anchor point
12181  *
12182  * Since: 1.0
12183  */
12184 ClutterGravity
12185 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12186 {
12187   const ClutterTransformInfo *info;
12188
12189   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12190
12191   info = _clutter_actor_get_transform_info_or_defaults (self);
12192
12193   return clutter_anchor_coord_get_gravity (&info->anchor);
12194 }
12195
12196 /**
12197  * clutter_actor_move_anchor_point:
12198  * @self: a #ClutterActor
12199  * @anchor_x: X coordinate of the anchor point
12200  * @anchor_y: Y coordinate of the anchor point
12201  *
12202  * Sets an anchor point for the actor, and adjusts the actor postion so that
12203  * the relative position of the actor toward its parent remains the same.
12204  *
12205  * Since: 0.6
12206  */
12207 void
12208 clutter_actor_move_anchor_point (ClutterActor *self,
12209                                  gfloat        anchor_x,
12210                                  gfloat        anchor_y)
12211 {
12212   gfloat old_anchor_x, old_anchor_y;
12213   const ClutterTransformInfo *info;
12214
12215   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12216
12217   info = _clutter_actor_get_transform_info (self);
12218   clutter_anchor_coord_get_units (self, &info->anchor,
12219                                   &old_anchor_x,
12220                                   &old_anchor_y,
12221                                   NULL);
12222
12223   g_object_freeze_notify (G_OBJECT (self));
12224
12225   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12226
12227   if (self->priv->position_set)
12228     clutter_actor_move_by (self,
12229                            anchor_x - old_anchor_x,
12230                            anchor_y - old_anchor_y);
12231
12232   g_object_thaw_notify (G_OBJECT (self));
12233 }
12234
12235 /**
12236  * clutter_actor_move_anchor_point_from_gravity:
12237  * @self: a #ClutterActor
12238  * @gravity: #ClutterGravity.
12239  *
12240  * Sets an anchor point on the actor based on the given gravity, adjusting the
12241  * actor postion so that its relative position within its parent remains
12242  * unchanged.
12243  *
12244  * Since version 1.0 the anchor point will be stored as a gravity so
12245  * that if the actor changes size then the anchor point will move. For
12246  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12247  * and later double the size of the actor, the anchor point will move
12248  * to the bottom right.
12249  *
12250  * Since: 0.6
12251  */
12252 void
12253 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12254                                               ClutterGravity  gravity)
12255 {
12256   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12257   const ClutterTransformInfo *info;
12258   ClutterActorPrivate *priv;
12259
12260   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12261
12262   priv = self->priv;
12263   info = _clutter_actor_get_transform_info (self);
12264
12265   g_object_freeze_notify (G_OBJECT (self));
12266
12267   clutter_anchor_coord_get_units (self, &info->anchor,
12268                                   &old_anchor_x,
12269                                   &old_anchor_y,
12270                                   NULL);
12271   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12272   clutter_anchor_coord_get_units (self, &info->anchor,
12273                                   &new_anchor_x,
12274                                   &new_anchor_y,
12275                                   NULL);
12276
12277   if (priv->position_set)
12278     clutter_actor_move_by (self,
12279                            new_anchor_x - old_anchor_x,
12280                            new_anchor_y - old_anchor_y);
12281
12282   g_object_thaw_notify (G_OBJECT (self));
12283 }
12284
12285 /**
12286  * clutter_actor_set_anchor_point_from_gravity:
12287  * @self: a #ClutterActor
12288  * @gravity: #ClutterGravity.
12289  *
12290  * Sets an anchor point on the actor, based on the given gravity (this is a
12291  * convenience function wrapping clutter_actor_set_anchor_point()).
12292  *
12293  * Since version 1.0 the anchor point will be stored as a gravity so
12294  * that if the actor changes size then the anchor point will move. For
12295  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12296  * and later double the size of the actor, the anchor point will move
12297  * to the bottom right.
12298  *
12299  * Since: 0.6
12300  */
12301 void
12302 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12303                                              ClutterGravity  gravity)
12304 {
12305   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12306
12307   if (gravity == CLUTTER_GRAVITY_NONE)
12308     clutter_actor_set_anchor_point (self, 0, 0);
12309   else
12310     {
12311       GObject *obj = G_OBJECT (self);
12312       ClutterTransformInfo *info;
12313
12314       g_object_freeze_notify (obj);
12315
12316       info = _clutter_actor_get_transform_info (self);
12317       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12318
12319       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12320       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12321       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12322
12323       self->priv->transform_valid = FALSE;
12324
12325       clutter_actor_queue_redraw (self);
12326
12327       g_object_thaw_notify (obj);
12328     }
12329 }
12330
12331 static void
12332 clutter_actor_store_content_box (ClutterActor *self,
12333                                  const ClutterActorBox *box)
12334 {
12335   if (box != NULL)
12336     {
12337       self->priv->content_box = *box;
12338       self->priv->content_box_valid = TRUE;
12339     }
12340   else
12341     self->priv->content_box_valid = FALSE;
12342
12343   clutter_actor_queue_redraw (self);
12344
12345   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12346 }
12347
12348 static void
12349 clutter_container_iface_init (ClutterContainerIface *iface)
12350 {
12351   /* we don't override anything, as ClutterContainer already has a default
12352    * implementation that we can use, and which calls into our own API.
12353    */
12354 }
12355
12356 typedef enum
12357 {
12358   PARSE_X,
12359   PARSE_Y,
12360   PARSE_WIDTH,
12361   PARSE_HEIGHT,
12362   PARSE_ANCHOR_X,
12363   PARSE_ANCHOR_Y
12364 } ParseDimension;
12365
12366 static gfloat
12367 parse_units (ClutterActor   *self,
12368              ParseDimension  dimension,
12369              JsonNode       *node)
12370 {
12371   GValue value = G_VALUE_INIT;
12372   gfloat retval = 0;
12373
12374   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12375     return 0;
12376
12377   json_node_get_value (node, &value);
12378
12379   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12380     {
12381       retval = (gfloat) g_value_get_int64 (&value);
12382     }
12383   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12384     {
12385       retval = g_value_get_double (&value);
12386     }
12387   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12388     {
12389       ClutterUnits units;
12390       gboolean res;
12391
12392       res = clutter_units_from_string (&units, g_value_get_string (&value));
12393       if (res)
12394         retval = clutter_units_to_pixels (&units);
12395       else
12396         {
12397           g_warning ("Invalid value '%s': integers, strings or floating point "
12398                      "values can be used for the x, y, width and height "
12399                      "properties. Valid modifiers for strings are 'px', 'mm', "
12400                      "'pt' and 'em'.",
12401                      g_value_get_string (&value));
12402           retval = 0;
12403         }
12404     }
12405   else
12406     {
12407       g_warning ("Invalid value of type '%s': integers, strings of floating "
12408                  "point values can be used for the x, y, width, height "
12409                  "anchor-x and anchor-y properties.",
12410                  g_type_name (G_VALUE_TYPE (&value)));
12411     }
12412
12413   g_value_unset (&value);
12414
12415   return retval;
12416 }
12417
12418 typedef struct {
12419   ClutterRotateAxis axis;
12420
12421   gdouble angle;
12422
12423   gfloat center_x;
12424   gfloat center_y;
12425   gfloat center_z;
12426 } RotationInfo;
12427
12428 static inline gboolean
12429 parse_rotation_array (ClutterActor *actor,
12430                       JsonArray    *array,
12431                       RotationInfo *info)
12432 {
12433   JsonNode *element;
12434
12435   if (json_array_get_length (array) != 2)
12436     return FALSE;
12437
12438   /* angle */
12439   element = json_array_get_element (array, 0);
12440   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12441     info->angle = json_node_get_double (element);
12442   else
12443     return FALSE;
12444
12445   /* center */
12446   element = json_array_get_element (array, 1);
12447   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12448     {
12449       JsonArray *center = json_node_get_array (element);
12450
12451       if (json_array_get_length (center) != 2)
12452         return FALSE;
12453
12454       switch (info->axis)
12455         {
12456         case CLUTTER_X_AXIS:
12457           info->center_y = parse_units (actor, PARSE_Y,
12458                                         json_array_get_element (center, 0));
12459           info->center_z = parse_units (actor, PARSE_Y,
12460                                         json_array_get_element (center, 1));
12461           return TRUE;
12462
12463         case CLUTTER_Y_AXIS:
12464           info->center_x = parse_units (actor, PARSE_X,
12465                                         json_array_get_element (center, 0));
12466           info->center_z = parse_units (actor, PARSE_X,
12467                                         json_array_get_element (center, 1));
12468           return TRUE;
12469
12470         case CLUTTER_Z_AXIS:
12471           info->center_x = parse_units (actor, PARSE_X,
12472                                         json_array_get_element (center, 0));
12473           info->center_y = parse_units (actor, PARSE_Y,
12474                                         json_array_get_element (center, 1));
12475           return TRUE;
12476         }
12477     }
12478
12479   return FALSE;
12480 }
12481
12482 static gboolean
12483 parse_rotation (ClutterActor *actor,
12484                 JsonNode     *node,
12485                 RotationInfo *info)
12486 {
12487   JsonArray *array;
12488   guint len, i;
12489   gboolean retval = FALSE;
12490
12491   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12492     {
12493       g_warning ("Invalid node of type '%s' found, expecting an array",
12494                  json_node_type_name (node));
12495       return FALSE;
12496     }
12497
12498   array = json_node_get_array (node);
12499   len = json_array_get_length (array);
12500
12501   for (i = 0; i < len; i++)
12502     {
12503       JsonNode *element = json_array_get_element (array, i);
12504       JsonObject *object;
12505       JsonNode *member;
12506
12507       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12508         {
12509           g_warning ("Invalid node of type '%s' found, expecting an object",
12510                      json_node_type_name (element));
12511           return FALSE;
12512         }
12513
12514       object = json_node_get_object (element);
12515
12516       if (json_object_has_member (object, "x-axis"))
12517         {
12518           member = json_object_get_member (object, "x-axis");
12519
12520           info->axis = CLUTTER_X_AXIS;
12521
12522           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12523             {
12524               info->angle = json_node_get_double (member);
12525               retval = TRUE;
12526             }
12527           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12528             retval = parse_rotation_array (actor,
12529                                            json_node_get_array (member),
12530                                            info);
12531           else
12532             retval = FALSE;
12533         }
12534       else if (json_object_has_member (object, "y-axis"))
12535         {
12536           member = json_object_get_member (object, "y-axis");
12537
12538           info->axis = CLUTTER_Y_AXIS;
12539
12540           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12541             {
12542               info->angle = json_node_get_double (member);
12543               retval = TRUE;
12544             }
12545           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12546             retval = parse_rotation_array (actor,
12547                                            json_node_get_array (member),
12548                                            info);
12549           else
12550             retval = FALSE;
12551         }
12552       else if (json_object_has_member (object, "z-axis"))
12553         {
12554           member = json_object_get_member (object, "z-axis");
12555
12556           info->axis = CLUTTER_Z_AXIS;
12557
12558           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12559             {
12560               info->angle = json_node_get_double (member);
12561               retval = TRUE;
12562             }
12563           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12564             retval = parse_rotation_array (actor,
12565                                            json_node_get_array (member),
12566                                            info);
12567           else
12568             retval = FALSE;
12569         }
12570     }
12571
12572   return retval;
12573 }
12574
12575 static GSList *
12576 parse_actor_metas (ClutterScript *script,
12577                    ClutterActor  *actor,
12578                    JsonNode      *node)
12579 {
12580   GList *elements, *l;
12581   GSList *retval = NULL;
12582
12583   if (!JSON_NODE_HOLDS_ARRAY (node))
12584     return NULL;
12585
12586   elements = json_array_get_elements (json_node_get_array (node));
12587
12588   for (l = elements; l != NULL; l = l->next)
12589     {
12590       JsonNode *element = l->data;
12591       const gchar *id_ = _clutter_script_get_id_from_node (element);
12592       GObject *meta;
12593
12594       if (id_ == NULL || *id_ == '\0')
12595         continue;
12596
12597       meta = clutter_script_get_object (script, id_);
12598       if (meta == NULL)
12599         continue;
12600
12601       retval = g_slist_prepend (retval, meta);
12602     }
12603
12604   g_list_free (elements);
12605
12606   return g_slist_reverse (retval);
12607 }
12608
12609 static GSList *
12610 parse_behaviours (ClutterScript *script,
12611                   ClutterActor  *actor,
12612                   JsonNode      *node)
12613 {
12614   GList *elements, *l;
12615   GSList *retval = NULL;
12616
12617   if (!JSON_NODE_HOLDS_ARRAY (node))
12618     return NULL;
12619
12620   elements = json_array_get_elements (json_node_get_array (node));
12621
12622   for (l = elements; l != NULL; l = l->next)
12623     {
12624       JsonNode *element = l->data;
12625       const gchar *id_ = _clutter_script_get_id_from_node (element);
12626       GObject *behaviour;
12627
12628       if (id_ == NULL || *id_ == '\0')
12629         continue;
12630
12631       behaviour = clutter_script_get_object (script, id_);
12632       if (behaviour == NULL)
12633         continue;
12634
12635       retval = g_slist_prepend (retval, behaviour);
12636     }
12637
12638   g_list_free (elements);
12639
12640   return g_slist_reverse (retval);
12641 }
12642
12643 static gboolean
12644 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12645                                  ClutterScript     *script,
12646                                  GValue            *value,
12647                                  const gchar       *name,
12648                                  JsonNode          *node)
12649 {
12650   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12651   gboolean retval = FALSE;
12652
12653   if ((name[0] == 'x' && name[1] == '\0') ||
12654       (name[0] == 'y' && name[1] == '\0') ||
12655       (strcmp (name, "width") == 0) ||
12656       (strcmp (name, "height") == 0) ||
12657       (strcmp (name, "anchor_x") == 0) ||
12658       (strcmp (name, "anchor_y") == 0))
12659     {
12660       ParseDimension dimension;
12661       gfloat units;
12662
12663       if (name[0] == 'x')
12664         dimension = PARSE_X;
12665       else if (name[0] == 'y')
12666         dimension = PARSE_Y;
12667       else if (name[0] == 'w')
12668         dimension = PARSE_WIDTH;
12669       else if (name[0] == 'h')
12670         dimension = PARSE_HEIGHT;
12671       else if (name[0] == 'a' && name[7] == 'x')
12672         dimension = PARSE_ANCHOR_X;
12673       else if (name[0] == 'a' && name[7] == 'y')
12674         dimension = PARSE_ANCHOR_Y;
12675       else
12676         return FALSE;
12677
12678       units = parse_units (actor, dimension, node);
12679
12680       /* convert back to pixels: all properties are pixel-based */
12681       g_value_init (value, G_TYPE_FLOAT);
12682       g_value_set_float (value, units);
12683
12684       retval = TRUE;
12685     }
12686   else if (strcmp (name, "rotation") == 0)
12687     {
12688       RotationInfo *info;
12689
12690       info = g_slice_new0 (RotationInfo);
12691       retval = parse_rotation (actor, node, info);
12692
12693       if (retval)
12694         {
12695           g_value_init (value, G_TYPE_POINTER);
12696           g_value_set_pointer (value, info);
12697         }
12698       else
12699         g_slice_free (RotationInfo, info);
12700     }
12701   else if (strcmp (name, "behaviours") == 0)
12702     {
12703       GSList *l;
12704
12705 #ifdef CLUTTER_ENABLE_DEBUG
12706       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12707         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12708                                      "and it should not be used in newly "
12709                                      "written ClutterScript definitions.");
12710 #endif
12711
12712       l = parse_behaviours (script, actor, node);
12713
12714       g_value_init (value, G_TYPE_POINTER);
12715       g_value_set_pointer (value, l);
12716
12717       retval = TRUE;
12718     }
12719   else if (strcmp (name, "actions") == 0 ||
12720            strcmp (name, "constraints") == 0 ||
12721            strcmp (name, "effects") == 0)
12722     {
12723       GSList *l;
12724
12725       l = parse_actor_metas (script, actor, node);
12726
12727       g_value_init (value, G_TYPE_POINTER);
12728       g_value_set_pointer (value, l);
12729
12730       retval = TRUE;
12731     }
12732
12733   return retval;
12734 }
12735
12736 static void
12737 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12738                                    ClutterScript     *script,
12739                                    const gchar       *name,
12740                                    const GValue      *value)
12741 {
12742   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12743
12744 #ifdef CLUTTER_ENABLE_DEBUG
12745   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12746     {
12747       gchar *tmp = g_strdup_value_contents (value);
12748
12749       CLUTTER_NOTE (SCRIPT,
12750                     "in ClutterActor::set_custom_property('%s') = %s",
12751                     name,
12752                     tmp);
12753
12754       g_free (tmp);
12755     }
12756 #endif /* CLUTTER_ENABLE_DEBUG */
12757
12758   if (strcmp (name, "rotation") == 0)
12759     {
12760       RotationInfo *info;
12761
12762       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12763         return;
12764
12765       info = g_value_get_pointer (value);
12766
12767       clutter_actor_set_rotation (actor,
12768                                   info->axis, info->angle,
12769                                   info->center_x,
12770                                   info->center_y,
12771                                   info->center_z);
12772
12773       g_slice_free (RotationInfo, info);
12774
12775       return;
12776     }
12777
12778   if (strcmp (name, "behaviours") == 0)
12779     {
12780       GSList *behaviours, *l;
12781
12782       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12783         return;
12784
12785       behaviours = g_value_get_pointer (value);
12786       for (l = behaviours; l != NULL; l = l->next)
12787         {
12788           ClutterBehaviour *behaviour = l->data;
12789
12790           clutter_behaviour_apply (behaviour, actor);
12791         }
12792
12793       g_slist_free (behaviours);
12794
12795       return;
12796     }
12797
12798   if (strcmp (name, "actions") == 0 ||
12799       strcmp (name, "constraints") == 0 ||
12800       strcmp (name, "effects") == 0)
12801     {
12802       GSList *metas, *l;
12803
12804       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12805         return;
12806
12807       metas = g_value_get_pointer (value);
12808       for (l = metas; l != NULL; l = l->next)
12809         {
12810           if (name[0] == 'a')
12811             clutter_actor_add_action (actor, l->data);
12812
12813           if (name[0] == 'c')
12814             clutter_actor_add_constraint (actor, l->data);
12815
12816           if (name[0] == 'e')
12817             clutter_actor_add_effect (actor, l->data);
12818         }
12819
12820       g_slist_free (metas);
12821
12822       return;
12823     }
12824
12825   g_object_set_property (G_OBJECT (scriptable), name, value);
12826 }
12827
12828 static void
12829 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12830 {
12831   iface->parse_custom_node = clutter_actor_parse_custom_node;
12832   iface->set_custom_property = clutter_actor_set_custom_property;
12833 }
12834
12835 static ClutterActorMeta *
12836 get_meta_from_animation_property (ClutterActor  *actor,
12837                                   const gchar   *name,
12838                                   gchar        **name_p)
12839 {
12840   ClutterActorPrivate *priv = actor->priv;
12841   ClutterActorMeta *meta = NULL;
12842   gchar **tokens;
12843
12844   /* if this is not a special property, fall through */
12845   if (name[0] != '@')
12846     return NULL;
12847
12848   /* detect the properties named using the following spec:
12849    *
12850    *   @<section>.<meta-name>.<property-name>
12851    *
12852    * where <section> can be one of the following:
12853    *
12854    *   - actions
12855    *   - constraints
12856    *   - effects
12857    *
12858    * and <meta-name> is the name set on a specific ActorMeta
12859    */
12860
12861   tokens = g_strsplit (name + 1, ".", -1);
12862   if (tokens == NULL || g_strv_length (tokens) != 3)
12863     {
12864       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12865                     name + 1);
12866       g_strfreev (tokens);
12867       return NULL;
12868     }
12869
12870   if (strcmp (tokens[0], "actions") == 0)
12871     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12872
12873   if (strcmp (tokens[0], "constraints") == 0)
12874     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12875
12876   if (strcmp (tokens[0], "effects") == 0)
12877     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12878
12879   if (name_p != NULL)
12880     *name_p = g_strdup (tokens[2]);
12881
12882   CLUTTER_NOTE (ANIMATION,
12883                 "Looking for property '%s' of object '%s' in section '%s'",
12884                 tokens[2],
12885                 tokens[1],
12886                 tokens[0]);
12887
12888   g_strfreev (tokens);
12889
12890   return meta;
12891 }
12892
12893 static GParamSpec *
12894 clutter_actor_find_property (ClutterAnimatable *animatable,
12895                              const gchar       *property_name)
12896 {
12897   ClutterActorMeta *meta = NULL;
12898   GObjectClass *klass = NULL;
12899   GParamSpec *pspec = NULL;
12900   gchar *p_name = NULL;
12901
12902   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12903                                            property_name,
12904                                            &p_name);
12905
12906   if (meta != NULL)
12907     {
12908       klass = G_OBJECT_GET_CLASS (meta);
12909
12910       pspec = g_object_class_find_property (klass, p_name);
12911     }
12912   else
12913     {
12914       klass = G_OBJECT_GET_CLASS (animatable);
12915
12916       pspec = g_object_class_find_property (klass, property_name);
12917     }
12918
12919   g_free (p_name);
12920
12921   return pspec;
12922 }
12923
12924 static void
12925 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12926                                  const gchar       *property_name,
12927                                  GValue            *initial)
12928 {
12929   ClutterActorMeta *meta = NULL;
12930   gchar *p_name = NULL;
12931
12932   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12933                                            property_name,
12934                                            &p_name);
12935
12936   if (meta != NULL)
12937     g_object_get_property (G_OBJECT (meta), p_name, initial);
12938   else
12939     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12940
12941   g_free (p_name);
12942 }
12943
12944 /*
12945  * clutter_actor_set_animatable_property:
12946  * @actor: a #ClutterActor
12947  * @prop_id: the paramspec id
12948  * @value: the value to set
12949  * @pspec: the paramspec
12950  *
12951  * Sets values of animatable properties.
12952  *
12953  * This is a variant of clutter_actor_set_property() that gets called
12954  * by the #ClutterAnimatable implementation of #ClutterActor for the
12955  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12956  * #GParamSpec.
12957  *
12958  * Unlike the implementation of #GObjectClass.set_property(), this
12959  * function will not update the interval if a transition involving an
12960  * animatable property is in progress - this avoids cycles with the
12961  * transition API calling the public API.
12962  */
12963 static void
12964 clutter_actor_set_animatable_property (ClutterActor *actor,
12965                                        guint         prop_id,
12966                                        const GValue *value,
12967                                        GParamSpec   *pspec)
12968 {
12969   GObject *obj = G_OBJECT (actor);
12970
12971   g_object_freeze_notify (obj);
12972
12973   switch (prop_id)
12974     {
12975     case PROP_X:
12976       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12977       break;
12978
12979     case PROP_Y:
12980       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12981       break;
12982
12983     case PROP_WIDTH:
12984       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12985       break;
12986
12987     case PROP_HEIGHT:
12988       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12989       break;
12990
12991     case PROP_DEPTH:
12992       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12993       break;
12994
12995     case PROP_OPACITY:
12996       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12997       break;
12998
12999     case PROP_BACKGROUND_COLOR:
13000       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13001       break;
13002
13003     case PROP_SCALE_X:
13004       clutter_actor_set_scale_factor_internal (actor,
13005                                                g_value_get_double (value),
13006                                                pspec);
13007       break;
13008
13009     case PROP_SCALE_Y:
13010       clutter_actor_set_scale_factor_internal (actor,
13011                                                g_value_get_double (value),
13012                                                pspec);
13013       break;
13014
13015     case PROP_ROTATION_ANGLE_X:
13016       clutter_actor_set_rotation_angle_internal (actor,
13017                                                  CLUTTER_X_AXIS,
13018                                                  g_value_get_double (value));
13019       break;
13020
13021     case PROP_ROTATION_ANGLE_Y:
13022       clutter_actor_set_rotation_angle_internal (actor,
13023                                                  CLUTTER_Y_AXIS,
13024                                                  g_value_get_double (value));
13025       break;
13026
13027     case PROP_ROTATION_ANGLE_Z:
13028       clutter_actor_set_rotation_angle_internal (actor,
13029                                                  CLUTTER_Z_AXIS,
13030                                                  g_value_get_double (value));
13031       break;
13032
13033     case PROP_CONTENT_BOX:
13034       clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13035       break;
13036
13037     default:
13038       g_object_set_property (obj, pspec->name, value);
13039       break;
13040     }
13041
13042   g_object_thaw_notify (obj);
13043 }
13044
13045 static void
13046 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13047                                const gchar       *property_name,
13048                                const GValue      *final)
13049 {
13050   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13051   ClutterActorMeta *meta = NULL;
13052   gchar *p_name = NULL;
13053
13054   meta = get_meta_from_animation_property (actor,
13055                                            property_name,
13056                                            &p_name);
13057   if (meta != NULL)
13058     g_object_set_property (G_OBJECT (meta), p_name, final);
13059   else
13060     {
13061       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13062       GParamSpec *pspec;
13063
13064       pspec = g_object_class_find_property (obj_class, property_name);
13065
13066       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13067         {
13068           /* XXX - I'm going to the special hell for this */
13069           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13070         }
13071       else
13072         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13073     }
13074
13075   g_free (p_name);
13076 }
13077
13078 static void
13079 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13080 {
13081   iface->find_property = clutter_actor_find_property;
13082   iface->get_initial_state = clutter_actor_get_initial_state;
13083   iface->set_final_state = clutter_actor_set_final_state;
13084 }
13085
13086 /**
13087  * clutter_actor_transform_stage_point:
13088  * @self: A #ClutterActor
13089  * @x: (in): x screen coordinate of the point to unproject
13090  * @y: (in): y screen coordinate of the point to unproject
13091  * @x_out: (out): return location for the unprojected x coordinance
13092  * @y_out: (out): return location for the unprojected y coordinance
13093  *
13094  * This function translates screen coordinates (@x, @y) to
13095  * coordinates relative to the actor. For example, it can be used to translate
13096  * screen events from global screen coordinates into actor-local coordinates.
13097  *
13098  * The conversion can fail, notably if the transform stack results in the
13099  * actor being projected on the screen as a mere line.
13100  *
13101  * The conversion should not be expected to be pixel-perfect due to the
13102  * nature of the operation. In general the error grows when the skewing
13103  * of the actor rectangle on screen increases.
13104  *
13105  * <note><para>This function can be computationally intensive.</para></note>
13106  *
13107  * <note><para>This function only works when the allocation is up-to-date,
13108  * i.e. inside of paint().</para></note>
13109  *
13110  * Return value: %TRUE if conversion was successful.
13111  *
13112  * Since: 0.6
13113  */
13114 gboolean
13115 clutter_actor_transform_stage_point (ClutterActor *self,
13116                                      gfloat        x,
13117                                      gfloat        y,
13118                                      gfloat       *x_out,
13119                                      gfloat       *y_out)
13120 {
13121   ClutterVertex v[4];
13122   float ST[3][3];
13123   float RQ[3][3];
13124   int du, dv, xi, yi;
13125   float px, py;
13126   float xf, yf, wf, det;
13127   ClutterActorPrivate *priv;
13128
13129   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13130
13131   priv = self->priv;
13132
13133   /* This implementation is based on the quad -> quad projection algorithm
13134    * described by Paul Heckbert in:
13135    *
13136    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13137    *
13138    * and the sample implementation at:
13139    *
13140    *   http://www.cs.cmu.edu/~ph/src/texfund/
13141    *
13142    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13143    * quad to rectangle only, which significantly simplifies things; the
13144    * function calls have been unrolled, and most of the math is done in fixed
13145    * point.
13146    */
13147
13148   clutter_actor_get_abs_allocation_vertices (self, v);
13149
13150   /* Keeping these as ints simplifies the multiplication (no significant
13151    * loss of precision here).
13152    */
13153   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13154   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13155
13156   if (!du || !dv)
13157     return FALSE;
13158
13159 #define UX2FP(x)        (x)
13160 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13161
13162   /* First, find mapping from unit uv square to xy quadrilateral; this
13163    * equivalent to the pmap_square_quad() functions in the sample
13164    * implementation, which we can simplify, since our target is always
13165    * a rectangle.
13166    */
13167   px = v[0].x - v[1].x + v[3].x - v[2].x;
13168   py = v[0].y - v[1].y + v[3].y - v[2].y;
13169
13170   if (!px && !py)
13171     {
13172       /* affine transform */
13173       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13174       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13175       RQ[2][0] = UX2FP (v[0].x);
13176       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13177       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13178       RQ[2][1] = UX2FP (v[0].y);
13179       RQ[0][2] = 0;
13180       RQ[1][2] = 0;
13181       RQ[2][2] = 1.0;
13182     }
13183   else
13184     {
13185       /* projective transform */
13186       double dx1, dx2, dy1, dy2, del;
13187
13188       dx1 = UX2FP (v[1].x - v[3].x);
13189       dx2 = UX2FP (v[2].x - v[3].x);
13190       dy1 = UX2FP (v[1].y - v[3].y);
13191       dy2 = UX2FP (v[2].y - v[3].y);
13192
13193       del = DET2FP (dx1, dx2, dy1, dy2);
13194       if (!del)
13195         return FALSE;
13196
13197       /*
13198        * The division here needs to be done in floating point for
13199        * precisions reasons.
13200        */
13201       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13202       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13203       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13204       RQ[2][2] = 1.0;
13205       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13206       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13207       RQ[2][0] = UX2FP (v[0].x);
13208       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13209       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13210       RQ[2][1] = UX2FP (v[0].y);
13211     }
13212
13213   /*
13214    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13215    * square. Since our rectangle is based at 0,0 we only need to scale.
13216    */
13217   RQ[0][0] /= du;
13218   RQ[1][0] /= dv;
13219   RQ[0][1] /= du;
13220   RQ[1][1] /= dv;
13221   RQ[0][2] /= du;
13222   RQ[1][2] /= dv;
13223
13224   /*
13225    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13226    * inverse of that.
13227    */
13228   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13229   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13230   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13231   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13232   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13233   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13234   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13235   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13236   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13237
13238   /*
13239    * Check the resulting matrix is OK.
13240    */
13241   det = (RQ[0][0] * ST[0][0])
13242       + (RQ[0][1] * ST[0][1])
13243       + (RQ[0][2] * ST[0][2]);
13244   if (!det)
13245     return FALSE;
13246
13247   /*
13248    * Now transform our point with the ST matrix; the notional w
13249    * coordinate is 1, hence the last part is simply added.
13250    */
13251   xi = (int) x;
13252   yi = (int) y;
13253
13254   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13255   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13256   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13257
13258   if (x_out)
13259     *x_out = xf / wf;
13260
13261   if (y_out)
13262     *y_out = yf / wf;
13263
13264 #undef UX2FP
13265 #undef DET2FP
13266
13267   return TRUE;
13268 }
13269
13270 /*
13271  * ClutterGeometry
13272  */
13273
13274 static ClutterGeometry*
13275 clutter_geometry_copy (const ClutterGeometry *geometry)
13276 {
13277   return g_slice_dup (ClutterGeometry, geometry);
13278 }
13279
13280 static void
13281 clutter_geometry_free (ClutterGeometry *geometry)
13282 {
13283   if (G_LIKELY (geometry != NULL))
13284     g_slice_free (ClutterGeometry, geometry);
13285 }
13286
13287 /**
13288  * clutter_geometry_union:
13289  * @geometry_a: a #ClutterGeometry
13290  * @geometry_b: another #ClutterGeometry
13291  * @result: (out): location to store the result
13292  *
13293  * Find the union of two rectangles represented as #ClutterGeometry.
13294  *
13295  * Since: 1.4
13296  */
13297 void
13298 clutter_geometry_union (const ClutterGeometry *geometry_a,
13299                         const ClutterGeometry *geometry_b,
13300                         ClutterGeometry       *result)
13301 {
13302   /* We don't try to handle rectangles that can't be represented
13303    * as a signed integer box */
13304   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13305   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13306   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13307                   geometry_b->x + (gint)geometry_b->width);
13308   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13309                   geometry_b->y + (gint)geometry_b->height);
13310   result->x = x_1;
13311   result->y = y_1;
13312   result->width = x_2 - x_1;
13313   result->height = y_2 - y_1;
13314 }
13315
13316 /**
13317  * clutter_geometry_intersects:
13318  * @geometry0: The first geometry to test
13319  * @geometry1: The second geometry to test
13320  *
13321  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13322  * they do else %FALSE.
13323  *
13324  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13325  * %FALSE.
13326  *
13327  * Since: 1.4
13328  */
13329 gboolean
13330 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13331                              const ClutterGeometry *geometry1)
13332 {
13333   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13334       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13335       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13336       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13337     return FALSE;
13338   else
13339     return TRUE;
13340 }
13341
13342 static gboolean
13343 clutter_geometry_progress (const GValue *a,
13344                            const GValue *b,
13345                            gdouble       progress,
13346                            GValue       *retval)
13347 {
13348   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13349   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13350   ClutterGeometry res = { 0, };
13351   gint a_width = a_geom->width;
13352   gint b_width = b_geom->width;
13353   gint a_height = a_geom->height;
13354   gint b_height = b_geom->height;
13355
13356   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13357   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13358
13359   res.width = a_width + (b_width - a_width) * progress;
13360   res.height = a_height + (b_height - a_height) * progress;
13361
13362   g_value_set_boxed (retval, &res);
13363
13364   return TRUE;
13365 }
13366
13367 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13368                                clutter_geometry_copy,
13369                                clutter_geometry_free,
13370                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13371
13372 /*
13373  * ClutterVertices
13374  */
13375
13376 /**
13377  * clutter_vertex_new:
13378  * @x: X coordinate
13379  * @y: Y coordinate
13380  * @z: Z coordinate
13381  *
13382  * Creates a new #ClutterVertex for the point in 3D space
13383  * identified by the 3 coordinates @x, @y, @z
13384  *
13385  * Return value: the newly allocate #ClutterVertex. Use
13386  *   clutter_vertex_free() to free the resources
13387  *
13388  * Since: 1.0
13389  */
13390 ClutterVertex *
13391 clutter_vertex_new (gfloat x,
13392                     gfloat y,
13393                     gfloat z)
13394 {
13395   ClutterVertex *vertex;
13396
13397   vertex = g_slice_new (ClutterVertex);
13398   clutter_vertex_init (vertex, x, y, z);
13399
13400   return vertex;
13401 }
13402
13403 /**
13404  * clutter_vertex_init:
13405  * @vertex: a #ClutterVertex
13406  * @x: X coordinate
13407  * @y: Y coordinate
13408  * @z: Z coordinate
13409  *
13410  * Initializes @vertex with the given coordinates.
13411  *
13412  * Since: 1.10
13413  */
13414 void
13415 clutter_vertex_init (ClutterVertex *vertex,
13416                      gfloat         x,
13417                      gfloat         y,
13418                      gfloat         z)
13419 {
13420   g_return_if_fail (vertex != NULL);
13421
13422   vertex->x = x;
13423   vertex->y = y;
13424   vertex->z = z;
13425 }
13426
13427 /**
13428  * clutter_vertex_copy:
13429  * @vertex: a #ClutterVertex
13430  *
13431  * Copies @vertex
13432  *
13433  * Return value: a newly allocated copy of #ClutterVertex. Use
13434  *   clutter_vertex_free() to free the allocated resources
13435  *
13436  * Since: 1.0
13437  */
13438 ClutterVertex *
13439 clutter_vertex_copy (const ClutterVertex *vertex)
13440 {
13441   if (G_LIKELY (vertex != NULL))
13442     return g_slice_dup (ClutterVertex, vertex);
13443
13444   return NULL;
13445 }
13446
13447 /**
13448  * clutter_vertex_free:
13449  * @vertex: a #ClutterVertex
13450  *
13451  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13452  *
13453  * Since: 1.0
13454  */
13455 void
13456 clutter_vertex_free (ClutterVertex *vertex)
13457 {
13458   if (G_UNLIKELY (vertex != NULL))
13459     g_slice_free (ClutterVertex, vertex);
13460 }
13461
13462 /**
13463  * clutter_vertex_equal:
13464  * @vertex_a: a #ClutterVertex
13465  * @vertex_b: a #ClutterVertex
13466  *
13467  * Compares @vertex_a and @vertex_b for equality
13468  *
13469  * Return value: %TRUE if the passed #ClutterVertex are equal
13470  *
13471  * Since: 1.0
13472  */
13473 gboolean
13474 clutter_vertex_equal (const ClutterVertex *vertex_a,
13475                       const ClutterVertex *vertex_b)
13476 {
13477   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13478
13479   if (vertex_a == vertex_b)
13480     return TRUE;
13481
13482   return vertex_a->x == vertex_b->x &&
13483          vertex_a->y == vertex_b->y &&
13484          vertex_a->z == vertex_b->z;
13485 }
13486
13487 static gboolean
13488 clutter_vertex_progress (const GValue *a,
13489                          const GValue *b,
13490                          gdouble       progress,
13491                          GValue       *retval)
13492 {
13493   const ClutterVertex *av = g_value_get_boxed (a);
13494   const ClutterVertex *bv = g_value_get_boxed (b);
13495   ClutterVertex res = { 0, };
13496
13497   res.x = av->x + (bv->x - av->x) * progress;
13498   res.y = av->y + (bv->y - av->y) * progress;
13499   res.z = av->z + (bv->z - av->z) * progress;
13500
13501   g_value_set_boxed (retval, &res);
13502
13503   return TRUE;
13504 }
13505
13506 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13507                                clutter_vertex_copy,
13508                                clutter_vertex_free,
13509                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13510
13511 /**
13512  * clutter_actor_is_rotated:
13513  * @self: a #ClutterActor
13514  *
13515  * Checks whether any rotation is applied to the actor.
13516  *
13517  * Return value: %TRUE if the actor is rotated.
13518  *
13519  * Since: 0.6
13520  */
13521 gboolean
13522 clutter_actor_is_rotated (ClutterActor *self)
13523 {
13524   const ClutterTransformInfo *info;
13525
13526   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13527
13528   info = _clutter_actor_get_transform_info_or_defaults (self);
13529
13530   if (info->rx_angle || info->ry_angle || info->rz_angle)
13531     return TRUE;
13532
13533   return FALSE;
13534 }
13535
13536 /**
13537  * clutter_actor_is_scaled:
13538  * @self: a #ClutterActor
13539  *
13540  * Checks whether the actor is scaled in either dimension.
13541  *
13542  * Return value: %TRUE if the actor is scaled.
13543  *
13544  * Since: 0.6
13545  */
13546 gboolean
13547 clutter_actor_is_scaled (ClutterActor *self)
13548 {
13549   const ClutterTransformInfo *info;
13550
13551   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13552
13553   info = _clutter_actor_get_transform_info_or_defaults (self);
13554
13555   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13556     return TRUE;
13557
13558   return FALSE;
13559 }
13560
13561 ClutterActor *
13562 _clutter_actor_get_stage_internal (ClutterActor *actor)
13563 {
13564   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13565     actor = actor->priv->parent;
13566
13567   return actor;
13568 }
13569
13570 /**
13571  * clutter_actor_get_stage:
13572  * @actor: a #ClutterActor
13573  *
13574  * Retrieves the #ClutterStage where @actor is contained.
13575  *
13576  * Return value: (transfer none) (type Clutter.Stage): the stage
13577  *   containing the actor, or %NULL
13578  *
13579  * Since: 0.8
13580  */
13581 ClutterActor *
13582 clutter_actor_get_stage (ClutterActor *actor)
13583 {
13584   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13585
13586   return _clutter_actor_get_stage_internal (actor);
13587 }
13588
13589 /**
13590  * clutter_actor_allocate_available_size:
13591  * @self: a #ClutterActor
13592  * @x: the actor's X coordinate
13593  * @y: the actor's Y coordinate
13594  * @available_width: the maximum available width, or -1 to use the
13595  *   actor's natural width
13596  * @available_height: the maximum available height, or -1 to use the
13597  *   actor's natural height
13598  * @flags: flags controlling the allocation
13599  *
13600  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13601  * preferred size, but limiting it to the maximum available width
13602  * and height provided.
13603  *
13604  * This function will do the right thing when dealing with the
13605  * actor's request mode.
13606  *
13607  * The implementation of this function is equivalent to:
13608  *
13609  * |[
13610  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13611  *     {
13612  *       clutter_actor_get_preferred_width (self, available_height,
13613  *                                          &amp;min_width,
13614  *                                          &amp;natural_width);
13615  *       width = CLAMP (natural_width, min_width, available_width);
13616  *
13617  *       clutter_actor_get_preferred_height (self, width,
13618  *                                           &amp;min_height,
13619  *                                           &amp;natural_height);
13620  *       height = CLAMP (natural_height, min_height, available_height);
13621  *     }
13622  *   else
13623  *     {
13624  *       clutter_actor_get_preferred_height (self, available_width,
13625  *                                           &amp;min_height,
13626  *                                           &amp;natural_height);
13627  *       height = CLAMP (natural_height, min_height, available_height);
13628  *
13629  *       clutter_actor_get_preferred_width (self, height,
13630  *                                          &amp;min_width,
13631  *                                          &amp;natural_width);
13632  *       width = CLAMP (natural_width, min_width, available_width);
13633  *     }
13634  *
13635  *   box.x1 = x; box.y1 = y;
13636  *   box.x2 = box.x1 + available_width;
13637  *   box.y2 = box.y1 + available_height;
13638  *   clutter_actor_allocate (self, &amp;box, flags);
13639  * ]|
13640  *
13641  * This function can be used by fluid layout managers to allocate
13642  * an actor's preferred size without making it bigger than the area
13643  * available for the container.
13644  *
13645  * Since: 1.0
13646  */
13647 void
13648 clutter_actor_allocate_available_size (ClutterActor           *self,
13649                                        gfloat                  x,
13650                                        gfloat                  y,
13651                                        gfloat                  available_width,
13652                                        gfloat                  available_height,
13653                                        ClutterAllocationFlags  flags)
13654 {
13655   ClutterActorPrivate *priv;
13656   gfloat width, height;
13657   gfloat min_width, min_height;
13658   gfloat natural_width, natural_height;
13659   ClutterActorBox box;
13660
13661   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13662
13663   priv = self->priv;
13664
13665   width = height = 0.0;
13666
13667   switch (priv->request_mode)
13668     {
13669     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13670       clutter_actor_get_preferred_width (self, available_height,
13671                                          &min_width,
13672                                          &natural_width);
13673       width  = CLAMP (natural_width, min_width, available_width);
13674
13675       clutter_actor_get_preferred_height (self, width,
13676                                           &min_height,
13677                                           &natural_height);
13678       height = CLAMP (natural_height, min_height, available_height);
13679       break;
13680
13681     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13682       clutter_actor_get_preferred_height (self, available_width,
13683                                           &min_height,
13684                                           &natural_height);
13685       height = CLAMP (natural_height, min_height, available_height);
13686
13687       clutter_actor_get_preferred_width (self, height,
13688                                          &min_width,
13689                                          &natural_width);
13690       width  = CLAMP (natural_width, min_width, available_width);
13691       break;
13692     }
13693
13694
13695   box.x1 = x;
13696   box.y1 = y;
13697   box.x2 = box.x1 + width;
13698   box.y2 = box.y1 + height;
13699   clutter_actor_allocate (self, &box, flags);
13700 }
13701
13702 /**
13703  * clutter_actor_allocate_preferred_size:
13704  * @self: a #ClutterActor
13705  * @flags: flags controlling the allocation
13706  *
13707  * Allocates the natural size of @self.
13708  *
13709  * This function is a utility call for #ClutterActor implementations
13710  * that allocates the actor's preferred natural size. It can be used
13711  * by fixed layout managers (like #ClutterGroup or so called
13712  * 'composite actors') inside the ClutterActor::allocate
13713  * implementation to give each child exactly how much space it
13714  * requires.
13715  *
13716  * This function is not meant to be used by applications. It is also
13717  * not meant to be used outside the implementation of the
13718  * ClutterActor::allocate virtual function.
13719  *
13720  * Since: 0.8
13721  */
13722 void
13723 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13724                                        ClutterAllocationFlags  flags)
13725 {
13726   gfloat actor_x, actor_y;
13727   gfloat natural_width, natural_height;
13728   ClutterActorBox actor_box;
13729
13730   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13731
13732   actor_x = clutter_actor_get_x (self);
13733   actor_y = clutter_actor_get_y (self);
13734
13735   clutter_actor_get_preferred_size (self,
13736                                     NULL, NULL,
13737                                     &natural_width,
13738                                     &natural_height);
13739
13740   actor_box.x1 = actor_x;
13741   actor_box.y1 = actor_y;
13742   actor_box.x2 = actor_box.x1 + natural_width;
13743   actor_box.y2 = actor_box.y1 + natural_height;
13744
13745   clutter_actor_allocate (self, &actor_box, flags);
13746 }
13747
13748 /**
13749  * clutter_actor_allocate_align_fill:
13750  * @self: a #ClutterActor
13751  * @box: a #ClutterActorBox, containing the available width and height
13752  * @x_align: the horizontal alignment, between 0 and 1
13753  * @y_align: the vertical alignment, between 0 and 1
13754  * @x_fill: whether the actor should fill horizontally
13755  * @y_fill: whether the actor should fill vertically
13756  * @flags: allocation flags to be passed to clutter_actor_allocate()
13757  *
13758  * Allocates @self by taking into consideration the available allocation
13759  * area; an alignment factor on either axis; and whether the actor should
13760  * fill the allocation on either axis.
13761  *
13762  * The @box should contain the available allocation width and height;
13763  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13764  * allocation will be offset by their value.
13765  *
13766  * This function takes into consideration the geometry request specified by
13767  * the #ClutterActor:request-mode property, and the text direction.
13768  *
13769  * This function is useful for fluid layout managers, like #ClutterBinLayout
13770  * or #ClutterTableLayout
13771  *
13772  * Since: 1.4
13773  */
13774 void
13775 clutter_actor_allocate_align_fill (ClutterActor           *self,
13776                                    const ClutterActorBox  *box,
13777                                    gdouble                 x_align,
13778                                    gdouble                 y_align,
13779                                    gboolean                x_fill,
13780                                    gboolean                y_fill,
13781                                    ClutterAllocationFlags  flags)
13782 {
13783   ClutterActorPrivate *priv;
13784   ClutterActorBox allocation = { 0, };
13785   gfloat x_offset, y_offset;
13786   gfloat available_width, available_height;
13787   gfloat child_width, child_height;
13788
13789   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13790   g_return_if_fail (box != NULL);
13791   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13792   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13793
13794   priv = self->priv;
13795
13796   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13797   clutter_actor_box_get_size (box, &available_width, &available_height);
13798
13799   if (available_width < 0)
13800     available_width = 0;
13801
13802   if (available_height < 0)
13803     available_height = 0;
13804
13805   if (x_fill)
13806     {
13807       allocation.x1 = x_offset;
13808       allocation.x2 = allocation.x1 + available_width;
13809     }
13810
13811   if (y_fill)
13812     {
13813       allocation.y1 = y_offset;
13814       allocation.y2 = allocation.y1 + available_height;
13815     }
13816
13817   /* if we are filling horizontally and vertically then we're done */
13818   if (x_fill && y_fill)
13819     goto out;
13820
13821   child_width = child_height = 0.0f;
13822
13823   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13824     {
13825       gfloat min_width, natural_width;
13826       gfloat min_height, natural_height;
13827
13828       clutter_actor_get_preferred_width (self, available_height,
13829                                          &min_width,
13830                                          &natural_width);
13831
13832       child_width = CLAMP (natural_width, min_width, available_width);
13833
13834       if (!y_fill)
13835         {
13836           clutter_actor_get_preferred_height (self, child_width,
13837                                               &min_height,
13838                                               &natural_height);
13839
13840           child_height = CLAMP (natural_height, min_height, available_height);
13841         }
13842     }
13843   else
13844     {
13845       gfloat min_width, natural_width;
13846       gfloat min_height, natural_height;
13847
13848       clutter_actor_get_preferred_height (self, available_width,
13849                                           &min_height,
13850                                           &natural_height);
13851
13852       child_height = CLAMP (natural_height, min_height, available_height);
13853
13854       if (!x_fill)
13855         {
13856           clutter_actor_get_preferred_width (self, child_height,
13857                                              &min_width,
13858                                              &natural_width);
13859
13860           child_width = CLAMP (natural_width, min_width, available_width);
13861         }
13862     }
13863
13864   /* invert the horizontal alignment for RTL languages */
13865   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13866     x_align = 1.0 - x_align;
13867
13868   if (!x_fill)
13869     {
13870       allocation.x1 = x_offset
13871                     + ((available_width - child_width) * x_align);
13872       allocation.x2 = allocation.x1 + child_width;
13873     }
13874
13875   if (!y_fill)
13876     {
13877       allocation.y1 = y_offset
13878                     + ((available_height - child_height) * y_align);
13879       allocation.y2 = allocation.y1 + child_height;
13880     }
13881
13882 out:
13883   clutter_actor_box_clamp_to_pixel (&allocation);
13884   clutter_actor_allocate (self, &allocation, flags);
13885 }
13886
13887 /**
13888  * clutter_actor_grab_key_focus:
13889  * @self: a #ClutterActor
13890  *
13891  * Sets the key focus of the #ClutterStage including @self
13892  * to this #ClutterActor.
13893  *
13894  * Since: 1.0
13895  */
13896 void
13897 clutter_actor_grab_key_focus (ClutterActor *self)
13898 {
13899   ClutterActor *stage;
13900
13901   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13902
13903   stage = _clutter_actor_get_stage_internal (self);
13904   if (stage != NULL)
13905     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13906 }
13907
13908 /**
13909  * clutter_actor_get_pango_context:
13910  * @self: a #ClutterActor
13911  *
13912  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13913  * is already configured using the appropriate font map, resolution
13914  * and font options.
13915  *
13916  * Unlike clutter_actor_create_pango_context(), this context is owend
13917  * by the #ClutterActor and it will be updated each time the options
13918  * stored by the #ClutterBackend change.
13919  *
13920  * You can use the returned #PangoContext to create a #PangoLayout
13921  * and render text using cogl_pango_render_layout() to reuse the
13922  * glyphs cache also used by Clutter.
13923  *
13924  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13925  *   The returned #PangoContext is owned by the actor and should not be
13926  *   unreferenced by the application code
13927  *
13928  * Since: 1.0
13929  */
13930 PangoContext *
13931 clutter_actor_get_pango_context (ClutterActor *self)
13932 {
13933   ClutterActorPrivate *priv;
13934
13935   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13936
13937   priv = self->priv;
13938
13939   if (priv->pango_context != NULL)
13940     return priv->pango_context;
13941
13942   priv->pango_context = _clutter_context_get_pango_context ();
13943   g_object_ref (priv->pango_context);
13944
13945   return priv->pango_context;
13946 }
13947
13948 /**
13949  * clutter_actor_create_pango_context:
13950  * @self: a #ClutterActor
13951  *
13952  * Creates a #PangoContext for the given actor. The #PangoContext
13953  * is already configured using the appropriate font map, resolution
13954  * and font options.
13955  *
13956  * See also clutter_actor_get_pango_context().
13957  *
13958  * Return value: (transfer full): the newly created #PangoContext.
13959  *   Use g_object_unref() on the returned value to deallocate its
13960  *   resources
13961  *
13962  * Since: 1.0
13963  */
13964 PangoContext *
13965 clutter_actor_create_pango_context (ClutterActor *self)
13966 {
13967   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13968
13969   return _clutter_context_create_pango_context ();
13970 }
13971
13972 /**
13973  * clutter_actor_create_pango_layout:
13974  * @self: a #ClutterActor
13975  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13976  *
13977  * Creates a new #PangoLayout from the same #PangoContext used
13978  * by the #ClutterActor. The #PangoLayout is already configured
13979  * with the font map, resolution and font options, and the
13980  * given @text.
13981  *
13982  * If you want to keep around a #PangoLayout created by this
13983  * function you will have to connect to the #ClutterBackend::font-changed
13984  * and #ClutterBackend::resolution-changed signals, and call
13985  * pango_layout_context_changed() in response to them.
13986  *
13987  * Return value: (transfer full): the newly created #PangoLayout.
13988  *   Use g_object_unref() when done
13989  *
13990  * Since: 1.0
13991  */
13992 PangoLayout *
13993 clutter_actor_create_pango_layout (ClutterActor *self,
13994                                    const gchar  *text)
13995 {
13996   PangoContext *context;
13997   PangoLayout *layout;
13998
13999   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14000
14001   context = clutter_actor_get_pango_context (self);
14002   layout = pango_layout_new (context);
14003
14004   if (text)
14005     pango_layout_set_text (layout, text, -1);
14006
14007   return layout;
14008 }
14009
14010 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14011  * ClutterOffscreenEffect.
14012  */
14013 void
14014 _clutter_actor_set_opacity_override (ClutterActor *self,
14015                                      gint          opacity)
14016 {
14017   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14018
14019   self->priv->opacity_override = opacity;
14020 }
14021
14022 gint
14023 _clutter_actor_get_opacity_override (ClutterActor *self)
14024 {
14025   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14026
14027   return self->priv->opacity_override;
14028 }
14029
14030 /* Allows you to disable applying the actors model view transform during
14031  * a paint. Used by ClutterClone. */
14032 void
14033 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14034                                                 gboolean      enable)
14035 {
14036   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14037
14038   self->priv->enable_model_view_transform = enable;
14039 }
14040
14041 void
14042 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14043                                           gboolean      enable)
14044 {
14045   ClutterActorPrivate *priv;
14046
14047   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14048
14049   priv = self->priv;
14050
14051   priv->enable_paint_unmapped = enable;
14052
14053   if (priv->enable_paint_unmapped)
14054     {
14055       /* Make sure that the parents of the widget are realized first;
14056        * otherwise checks in clutter_actor_update_map_state() will
14057        * fail.
14058        */
14059       clutter_actor_realize (self);
14060
14061       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14062     }
14063   else
14064     {
14065       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14066     }
14067 }
14068
14069 static void
14070 clutter_anchor_coord_get_units (ClutterActor      *self,
14071                                 const AnchorCoord *coord,
14072                                 gfloat            *x,
14073                                 gfloat            *y,
14074                                 gfloat            *z)
14075 {
14076   if (coord->is_fractional)
14077     {
14078       gfloat actor_width, actor_height;
14079
14080       clutter_actor_get_size (self, &actor_width, &actor_height);
14081
14082       if (x)
14083         *x = actor_width * coord->v.fraction.x;
14084
14085       if (y)
14086         *y = actor_height * coord->v.fraction.y;
14087
14088       if (z)
14089         *z = 0;
14090     }
14091   else
14092     {
14093       if (x)
14094         *x = coord->v.units.x;
14095
14096       if (y)
14097         *y = coord->v.units.y;
14098
14099       if (z)
14100         *z = coord->v.units.z;
14101     }
14102 }
14103
14104 static void
14105 clutter_anchor_coord_set_units (AnchorCoord *coord,
14106                                 gfloat       x,
14107                                 gfloat       y,
14108                                 gfloat       z)
14109 {
14110   coord->is_fractional = FALSE;
14111   coord->v.units.x = x;
14112   coord->v.units.y = y;
14113   coord->v.units.z = z;
14114 }
14115
14116 static ClutterGravity
14117 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14118 {
14119   if (coord->is_fractional)
14120     {
14121       if (coord->v.fraction.x == 0.0)
14122         {
14123           if (coord->v.fraction.y == 0.0)
14124             return CLUTTER_GRAVITY_NORTH_WEST;
14125           else if (coord->v.fraction.y == 0.5)
14126             return CLUTTER_GRAVITY_WEST;
14127           else if (coord->v.fraction.y == 1.0)
14128             return CLUTTER_GRAVITY_SOUTH_WEST;
14129           else
14130             return CLUTTER_GRAVITY_NONE;
14131         }
14132       else if (coord->v.fraction.x == 0.5)
14133         {
14134           if (coord->v.fraction.y == 0.0)
14135             return CLUTTER_GRAVITY_NORTH;
14136           else if (coord->v.fraction.y == 0.5)
14137             return CLUTTER_GRAVITY_CENTER;
14138           else if (coord->v.fraction.y == 1.0)
14139             return CLUTTER_GRAVITY_SOUTH;
14140           else
14141             return CLUTTER_GRAVITY_NONE;
14142         }
14143       else if (coord->v.fraction.x == 1.0)
14144         {
14145           if (coord->v.fraction.y == 0.0)
14146             return CLUTTER_GRAVITY_NORTH_EAST;
14147           else if (coord->v.fraction.y == 0.5)
14148             return CLUTTER_GRAVITY_EAST;
14149           else if (coord->v.fraction.y == 1.0)
14150             return CLUTTER_GRAVITY_SOUTH_EAST;
14151           else
14152             return CLUTTER_GRAVITY_NONE;
14153         }
14154       else
14155         return CLUTTER_GRAVITY_NONE;
14156     }
14157   else
14158     return CLUTTER_GRAVITY_NONE;
14159 }
14160
14161 static void
14162 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14163                                   ClutterGravity  gravity)
14164 {
14165   switch (gravity)
14166     {
14167     case CLUTTER_GRAVITY_NORTH:
14168       coord->v.fraction.x = 0.5;
14169       coord->v.fraction.y = 0.0;
14170       break;
14171
14172     case CLUTTER_GRAVITY_NORTH_EAST:
14173       coord->v.fraction.x = 1.0;
14174       coord->v.fraction.y = 0.0;
14175       break;
14176
14177     case CLUTTER_GRAVITY_EAST:
14178       coord->v.fraction.x = 1.0;
14179       coord->v.fraction.y = 0.5;
14180       break;
14181
14182     case CLUTTER_GRAVITY_SOUTH_EAST:
14183       coord->v.fraction.x = 1.0;
14184       coord->v.fraction.y = 1.0;
14185       break;
14186
14187     case CLUTTER_GRAVITY_SOUTH:
14188       coord->v.fraction.x = 0.5;
14189       coord->v.fraction.y = 1.0;
14190       break;
14191
14192     case CLUTTER_GRAVITY_SOUTH_WEST:
14193       coord->v.fraction.x = 0.0;
14194       coord->v.fraction.y = 1.0;
14195       break;
14196
14197     case CLUTTER_GRAVITY_WEST:
14198       coord->v.fraction.x = 0.0;
14199       coord->v.fraction.y = 0.5;
14200       break;
14201
14202     case CLUTTER_GRAVITY_NORTH_WEST:
14203       coord->v.fraction.x = 0.0;
14204       coord->v.fraction.y = 0.0;
14205       break;
14206
14207     case CLUTTER_GRAVITY_CENTER:
14208       coord->v.fraction.x = 0.5;
14209       coord->v.fraction.y = 0.5;
14210       break;
14211
14212     default:
14213       coord->v.fraction.x = 0.0;
14214       coord->v.fraction.y = 0.0;
14215       break;
14216     }
14217
14218   coord->is_fractional = TRUE;
14219 }
14220
14221 static gboolean
14222 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14223 {
14224   if (coord->is_fractional)
14225     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14226   else
14227     return (coord->v.units.x == 0.0
14228             && coord->v.units.y == 0.0
14229             && coord->v.units.z == 0.0);
14230 }
14231
14232 /**
14233  * clutter_actor_get_flags:
14234  * @self: a #ClutterActor
14235  *
14236  * Retrieves the flags set on @self
14237  *
14238  * Return value: a bitwise or of #ClutterActorFlags or 0
14239  *
14240  * Since: 1.0
14241  */
14242 ClutterActorFlags
14243 clutter_actor_get_flags (ClutterActor *self)
14244 {
14245   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14246
14247   return self->flags;
14248 }
14249
14250 /**
14251  * clutter_actor_set_flags:
14252  * @self: a #ClutterActor
14253  * @flags: the flags to set
14254  *
14255  * Sets @flags on @self
14256  *
14257  * This function will emit notifications for the changed properties
14258  *
14259  * Since: 1.0
14260  */
14261 void
14262 clutter_actor_set_flags (ClutterActor      *self,
14263                          ClutterActorFlags  flags)
14264 {
14265   ClutterActorFlags old_flags;
14266   GObject *obj;
14267   gboolean was_reactive_set, reactive_set;
14268   gboolean was_realized_set, realized_set;
14269   gboolean was_mapped_set, mapped_set;
14270   gboolean was_visible_set, visible_set;
14271
14272   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14273
14274   if (self->flags == flags)
14275     return;
14276
14277   obj = G_OBJECT (self);
14278   g_object_ref (obj);
14279   g_object_freeze_notify (obj);
14280
14281   old_flags = self->flags;
14282
14283   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14284   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14285   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14286   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14287
14288   self->flags |= flags;
14289
14290   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14291   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14292   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14293   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14294
14295   if (reactive_set != was_reactive_set)
14296     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14297
14298   if (realized_set != was_realized_set)
14299     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14300
14301   if (mapped_set != was_mapped_set)
14302     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14303
14304   if (visible_set != was_visible_set)
14305     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14306
14307   g_object_thaw_notify (obj);
14308   g_object_unref (obj);
14309 }
14310
14311 /**
14312  * clutter_actor_unset_flags:
14313  * @self: a #ClutterActor
14314  * @flags: the flags to unset
14315  *
14316  * Unsets @flags on @self
14317  *
14318  * This function will emit notifications for the changed properties
14319  *
14320  * Since: 1.0
14321  */
14322 void
14323 clutter_actor_unset_flags (ClutterActor      *self,
14324                            ClutterActorFlags  flags)
14325 {
14326   ClutterActorFlags old_flags;
14327   GObject *obj;
14328   gboolean was_reactive_set, reactive_set;
14329   gboolean was_realized_set, realized_set;
14330   gboolean was_mapped_set, mapped_set;
14331   gboolean was_visible_set, visible_set;
14332
14333   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14334
14335   obj = G_OBJECT (self);
14336   g_object_freeze_notify (obj);
14337
14338   old_flags = self->flags;
14339
14340   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14341   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14342   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14343   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14344
14345   self->flags &= ~flags;
14346
14347   if (self->flags == old_flags)
14348     return;
14349
14350   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14351   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14352   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14353   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14354
14355   if (reactive_set != was_reactive_set)
14356     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14357
14358   if (realized_set != was_realized_set)
14359     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14360
14361   if (mapped_set != was_mapped_set)
14362     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14363
14364   if (visible_set != was_visible_set)
14365     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14366
14367   g_object_thaw_notify (obj);
14368 }
14369
14370 /**
14371  * clutter_actor_get_transformation_matrix:
14372  * @self: a #ClutterActor
14373  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14374  *
14375  * Retrieves the transformations applied to @self relative to its
14376  * parent.
14377  *
14378  * Since: 1.0
14379  */
14380 void
14381 clutter_actor_get_transformation_matrix (ClutterActor *self,
14382                                          CoglMatrix   *matrix)
14383 {
14384   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14385
14386   cogl_matrix_init_identity (matrix);
14387
14388   _clutter_actor_apply_modelview_transform (self, matrix);
14389 }
14390
14391 void
14392 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14393                                    gboolean      is_in_clone_paint)
14394 {
14395   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14396   self->priv->in_clone_paint = is_in_clone_paint;
14397 }
14398
14399 /**
14400  * clutter_actor_is_in_clone_paint:
14401  * @self: a #ClutterActor
14402  *
14403  * Checks whether @self is being currently painted by a #ClutterClone
14404  *
14405  * This function is useful only inside the ::paint virtual function
14406  * implementations or within handlers for the #ClutterActor::paint
14407  * signal
14408  *
14409  * This function should not be used by applications
14410  *
14411  * Return value: %TRUE if the #ClutterActor is currently being painted
14412  *   by a #ClutterClone, and %FALSE otherwise
14413  *
14414  * Since: 1.0
14415  */
14416 gboolean
14417 clutter_actor_is_in_clone_paint (ClutterActor *self)
14418 {
14419   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14420
14421   return self->priv->in_clone_paint;
14422 }
14423
14424 static gboolean
14425 set_direction_recursive (ClutterActor *actor,
14426                          gpointer      user_data)
14427 {
14428   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14429
14430   clutter_actor_set_text_direction (actor, text_dir);
14431
14432   return TRUE;
14433 }
14434
14435 /**
14436  * clutter_actor_set_text_direction:
14437  * @self: a #ClutterActor
14438  * @text_dir: the text direction for @self
14439  *
14440  * Sets the #ClutterTextDirection for an actor
14441  *
14442  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14443  *
14444  * If @self implements #ClutterContainer then this function will recurse
14445  * inside all the children of @self (including the internal ones).
14446  *
14447  * Composite actors not implementing #ClutterContainer, or actors requiring
14448  * special handling when the text direction changes, should connect to
14449  * the #GObject::notify signal for the #ClutterActor:text-direction property
14450  *
14451  * Since: 1.2
14452  */
14453 void
14454 clutter_actor_set_text_direction (ClutterActor         *self,
14455                                   ClutterTextDirection  text_dir)
14456 {
14457   ClutterActorPrivate *priv;
14458
14459   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14460   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14461
14462   priv = self->priv;
14463
14464   if (priv->text_direction != text_dir)
14465     {
14466       priv->text_direction = text_dir;
14467
14468       /* we need to emit the notify::text-direction first, so that
14469        * the sub-classes can catch that and do specific handling of
14470        * the text direction; see clutter_text_direction_changed_cb()
14471        * inside clutter-text.c
14472        */
14473       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14474
14475       _clutter_actor_foreach_child (self, set_direction_recursive,
14476                                     GINT_TO_POINTER (text_dir));
14477
14478       clutter_actor_queue_relayout (self);
14479     }
14480 }
14481
14482 void
14483 _clutter_actor_set_has_pointer (ClutterActor *self,
14484                                 gboolean      has_pointer)
14485 {
14486   ClutterActorPrivate *priv = self->priv;
14487
14488   if (priv->has_pointer != has_pointer)
14489     {
14490       priv->has_pointer = has_pointer;
14491
14492       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14493     }
14494 }
14495
14496 /**
14497  * clutter_actor_get_text_direction:
14498  * @self: a #ClutterActor
14499  *
14500  * Retrieves the value set using clutter_actor_set_text_direction()
14501  *
14502  * If no text direction has been previously set, the default text
14503  * direction, as returned by clutter_get_default_text_direction(), will
14504  * be returned instead
14505  *
14506  * Return value: the #ClutterTextDirection for the actor
14507  *
14508  * Since: 1.2
14509  */
14510 ClutterTextDirection
14511 clutter_actor_get_text_direction (ClutterActor *self)
14512 {
14513   ClutterActorPrivate *priv;
14514
14515   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14516                         CLUTTER_TEXT_DIRECTION_LTR);
14517
14518   priv = self->priv;
14519
14520   /* if no direction has been set yet use the default */
14521   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14522     priv->text_direction = clutter_get_default_text_direction ();
14523
14524   return priv->text_direction;
14525 }
14526
14527 /**
14528  * clutter_actor_push_internal:
14529  * @self: a #ClutterActor
14530  *
14531  * Should be used by actors implementing the #ClutterContainer and with
14532  * internal children added through clutter_actor_set_parent(), for instance:
14533  *
14534  * |[
14535  *   static void
14536  *   my_actor_init (MyActor *self)
14537  *   {
14538  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14539  *
14540  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14541  *
14542  *     /&ast; calling clutter_actor_set_parent() now will result in
14543  *      &ast; the internal flag being set on a child of MyActor
14544  *      &ast;/
14545  *
14546  *     /&ast; internal child - a background texture &ast;/
14547  *     self->priv->background_tex = clutter_texture_new ();
14548  *     clutter_actor_set_parent (self->priv->background_tex,
14549  *                               CLUTTER_ACTOR (self));
14550  *
14551  *     /&ast; internal child - a label &ast;/
14552  *     self->priv->label = clutter_text_new ();
14553  *     clutter_actor_set_parent (self->priv->label,
14554  *                               CLUTTER_ACTOR (self));
14555  *
14556  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14557  *
14558  *     /&ast; calling clutter_actor_set_parent() now will not result in
14559  *      &ast; the internal flag being set on a child of MyActor
14560  *      &ast;/
14561  *   }
14562  * ]|
14563  *
14564  * This function will be used by Clutter to toggle an "internal child"
14565  * flag whenever clutter_actor_set_parent() is called; internal children
14566  * are handled differently by Clutter, specifically when destroying their
14567  * parent.
14568  *
14569  * Call clutter_actor_pop_internal() when you finished adding internal
14570  * children.
14571  *
14572  * Nested calls to clutter_actor_push_internal() are allowed, but each
14573  * one must by followed by a clutter_actor_pop_internal() call.
14574  *
14575  * Since: 1.2
14576  *
14577  * Deprecated: 1.10: All children of an actor are accessible through
14578  *   the #ClutterActor API, and #ClutterActor implements the
14579  *   #ClutterContainer interface, so this function is only useful
14580  *   for legacy containers overriding the default implementation.
14581  */
14582 void
14583 clutter_actor_push_internal (ClutterActor *self)
14584 {
14585   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14586
14587   self->priv->internal_child += 1;
14588 }
14589
14590 /**
14591  * clutter_actor_pop_internal:
14592  * @self: a #ClutterActor
14593  *
14594  * Disables the effects of clutter_actor_push_internal().
14595  *
14596  * Since: 1.2
14597  *
14598  * Deprecated: 1.10: All children of an actor are accessible through
14599  *   the #ClutterActor API. This function is only useful for legacy
14600  *   containers overriding the default implementation of the
14601  *   #ClutterContainer interface.
14602  */
14603 void
14604 clutter_actor_pop_internal (ClutterActor *self)
14605 {
14606   ClutterActorPrivate *priv;
14607
14608   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14609
14610   priv = self->priv;
14611
14612   if (priv->internal_child == 0)
14613     {
14614       g_warning ("Mismatched %s: you need to call "
14615                  "clutter_actor_push_composite() at least once before "
14616                  "calling this function", G_STRFUNC);
14617       return;
14618     }
14619
14620   priv->internal_child -= 1;
14621 }
14622
14623 /**
14624  * clutter_actor_has_pointer:
14625  * @self: a #ClutterActor
14626  *
14627  * Checks whether an actor contains the pointer of a
14628  * #ClutterInputDevice
14629  *
14630  * Return value: %TRUE if the actor contains the pointer, and
14631  *   %FALSE otherwise
14632  *
14633  * Since: 1.2
14634  */
14635 gboolean
14636 clutter_actor_has_pointer (ClutterActor *self)
14637 {
14638   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14639
14640   return self->priv->has_pointer;
14641 }
14642
14643 /* XXX: This is a workaround for not being able to break the ABI of
14644  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14645  * clutter_actor_queue_clipped_redraw() for details.
14646  */
14647 ClutterPaintVolume *
14648 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14649 {
14650   return g_object_get_data (G_OBJECT (self),
14651                             "-clutter-actor-queue-redraw-clip");
14652 }
14653
14654 void
14655 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14656                                       ClutterPaintVolume *clip)
14657 {
14658   g_object_set_data (G_OBJECT (self),
14659                      "-clutter-actor-queue-redraw-clip",
14660                      clip);
14661 }
14662
14663 /**
14664  * clutter_actor_has_allocation:
14665  * @self: a #ClutterActor
14666  *
14667  * Checks if the actor has an up-to-date allocation assigned to
14668  * it. This means that the actor should have an allocation: it's
14669  * visible and has a parent. It also means that there is no
14670  * outstanding relayout request in progress for the actor or its
14671  * children (There might be other outstanding layout requests in
14672  * progress that will cause the actor to get a new allocation
14673  * when the stage is laid out, however).
14674  *
14675  * If this function returns %FALSE, then the actor will normally
14676  * be allocated before it is next drawn on the screen.
14677  *
14678  * Return value: %TRUE if the actor has an up-to-date allocation
14679  *
14680  * Since: 1.4
14681  */
14682 gboolean
14683 clutter_actor_has_allocation (ClutterActor *self)
14684 {
14685   ClutterActorPrivate *priv;
14686
14687   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14688
14689   priv = self->priv;
14690
14691   return priv->parent != NULL &&
14692          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14693          !priv->needs_allocation;
14694 }
14695
14696 /**
14697  * clutter_actor_add_action:
14698  * @self: a #ClutterActor
14699  * @action: a #ClutterAction
14700  *
14701  * Adds @action to the list of actions applied to @self
14702  *
14703  * A #ClutterAction can only belong to one actor at a time
14704  *
14705  * The #ClutterActor will hold a reference on @action until either
14706  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14707  * is called
14708  *
14709  * Since: 1.4
14710  */
14711 void
14712 clutter_actor_add_action (ClutterActor  *self,
14713                           ClutterAction *action)
14714 {
14715   ClutterActorPrivate *priv;
14716
14717   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14718   g_return_if_fail (CLUTTER_IS_ACTION (action));
14719
14720   priv = self->priv;
14721
14722   if (priv->actions == NULL)
14723     {
14724       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14725       priv->actions->actor = self;
14726     }
14727
14728   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14729
14730   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14731 }
14732
14733 /**
14734  * clutter_actor_add_action_with_name:
14735  * @self: a #ClutterActor
14736  * @name: the name to set on the action
14737  * @action: a #ClutterAction
14738  *
14739  * A convenience function for setting the name of a #ClutterAction
14740  * while adding it to the list of actions applied to @self
14741  *
14742  * This function is the logical equivalent of:
14743  *
14744  * |[
14745  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14746  *   clutter_actor_add_action (self, action);
14747  * ]|
14748  *
14749  * Since: 1.4
14750  */
14751 void
14752 clutter_actor_add_action_with_name (ClutterActor  *self,
14753                                     const gchar   *name,
14754                                     ClutterAction *action)
14755 {
14756   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14757   g_return_if_fail (name != NULL);
14758   g_return_if_fail (CLUTTER_IS_ACTION (action));
14759
14760   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14761   clutter_actor_add_action (self, action);
14762 }
14763
14764 /**
14765  * clutter_actor_remove_action:
14766  * @self: a #ClutterActor
14767  * @action: a #ClutterAction
14768  *
14769  * Removes @action from the list of actions applied to @self
14770  *
14771  * The reference held by @self on the #ClutterAction will be released
14772  *
14773  * Since: 1.4
14774  */
14775 void
14776 clutter_actor_remove_action (ClutterActor  *self,
14777                              ClutterAction *action)
14778 {
14779   ClutterActorPrivate *priv;
14780
14781   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14782   g_return_if_fail (CLUTTER_IS_ACTION (action));
14783
14784   priv = self->priv;
14785
14786   if (priv->actions == NULL)
14787     return;
14788
14789   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14790
14791   if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
14792     g_clear_object (&priv->actions);
14793
14794   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14795 }
14796
14797 /**
14798  * clutter_actor_remove_action_by_name:
14799  * @self: a #ClutterActor
14800  * @name: the name of the action to remove
14801  *
14802  * Removes the #ClutterAction with the given name from the list
14803  * of actions applied to @self
14804  *
14805  * Since: 1.4
14806  */
14807 void
14808 clutter_actor_remove_action_by_name (ClutterActor *self,
14809                                      const gchar  *name)
14810 {
14811   ClutterActorPrivate *priv;
14812   ClutterActorMeta *meta;
14813
14814   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14815   g_return_if_fail (name != NULL);
14816
14817   priv = self->priv;
14818
14819   if (priv->actions == NULL)
14820     return;
14821
14822   meta = _clutter_meta_group_get_meta (priv->actions, name);
14823   if (meta == NULL)
14824     return;
14825
14826   _clutter_meta_group_remove_meta (priv->actions, meta);
14827
14828   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14829 }
14830
14831 /**
14832  * clutter_actor_get_actions:
14833  * @self: a #ClutterActor
14834  *
14835  * Retrieves the list of actions applied to @self
14836  *
14837  * Return value: (transfer container) (element-type Clutter.Action): a copy
14838  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14839  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14840  *   allocated by the returned #GList
14841  *
14842  * Since: 1.4
14843  */
14844 GList *
14845 clutter_actor_get_actions (ClutterActor *self)
14846 {
14847   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14848
14849   if (self->priv->actions == NULL)
14850     return NULL;
14851
14852   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14853 }
14854
14855 /**
14856  * clutter_actor_get_action:
14857  * @self: a #ClutterActor
14858  * @name: the name of the action to retrieve
14859  *
14860  * Retrieves the #ClutterAction with the given name in the list
14861  * of actions applied to @self
14862  *
14863  * Return value: (transfer none): a #ClutterAction for the given
14864  *   name, or %NULL. The returned #ClutterAction is owned by the
14865  *   actor and it should not be unreferenced directly
14866  *
14867  * Since: 1.4
14868  */
14869 ClutterAction *
14870 clutter_actor_get_action (ClutterActor *self,
14871                           const gchar  *name)
14872 {
14873   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14874   g_return_val_if_fail (name != NULL, NULL);
14875
14876   if (self->priv->actions == NULL)
14877     return NULL;
14878
14879   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14880 }
14881
14882 /**
14883  * clutter_actor_clear_actions:
14884  * @self: a #ClutterActor
14885  *
14886  * Clears the list of actions applied to @self
14887  *
14888  * Since: 1.4
14889  */
14890 void
14891 clutter_actor_clear_actions (ClutterActor *self)
14892 {
14893   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14894
14895   if (self->priv->actions == NULL)
14896     return;
14897
14898   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14899 }
14900
14901 /**
14902  * clutter_actor_add_constraint:
14903  * @self: a #ClutterActor
14904  * @constraint: a #ClutterConstraint
14905  *
14906  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14907  * to @self
14908  *
14909  * The #ClutterActor will hold a reference on the @constraint until
14910  * either clutter_actor_remove_constraint() or
14911  * clutter_actor_clear_constraints() is called.
14912  *
14913  * Since: 1.4
14914  */
14915 void
14916 clutter_actor_add_constraint (ClutterActor      *self,
14917                               ClutterConstraint *constraint)
14918 {
14919   ClutterActorPrivate *priv;
14920
14921   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14922   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14923
14924   priv = self->priv;
14925
14926   if (priv->constraints == NULL)
14927     {
14928       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14929       priv->constraints->actor = self;
14930     }
14931
14932   _clutter_meta_group_add_meta (priv->constraints,
14933                                 CLUTTER_ACTOR_META (constraint));
14934   clutter_actor_queue_relayout (self);
14935
14936   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14937 }
14938
14939 /**
14940  * clutter_actor_add_constraint_with_name:
14941  * @self: a #ClutterActor
14942  * @name: the name to set on the constraint
14943  * @constraint: a #ClutterConstraint
14944  *
14945  * A convenience function for setting the name of a #ClutterConstraint
14946  * while adding it to the list of constraints applied to @self
14947  *
14948  * This function is the logical equivalent of:
14949  *
14950  * |[
14951  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14952  *   clutter_actor_add_constraint (self, constraint);
14953  * ]|
14954  *
14955  * Since: 1.4
14956  */
14957 void
14958 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14959                                         const gchar       *name,
14960                                         ClutterConstraint *constraint)
14961 {
14962   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14963   g_return_if_fail (name != NULL);
14964   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14965
14966   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14967   clutter_actor_add_constraint (self, constraint);
14968 }
14969
14970 /**
14971  * clutter_actor_remove_constraint:
14972  * @self: a #ClutterActor
14973  * @constraint: a #ClutterConstraint
14974  *
14975  * Removes @constraint from the list of constraints applied to @self
14976  *
14977  * The reference held by @self on the #ClutterConstraint will be released
14978  *
14979  * Since: 1.4
14980  */
14981 void
14982 clutter_actor_remove_constraint (ClutterActor      *self,
14983                                  ClutterConstraint *constraint)
14984 {
14985   ClutterActorPrivate *priv;
14986
14987   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14988   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14989
14990   priv = self->priv;
14991
14992   if (priv->constraints == NULL)
14993     return;
14994
14995   _clutter_meta_group_remove_meta (priv->constraints,
14996                                    CLUTTER_ACTOR_META (constraint));
14997
14998   if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
14999     g_clear_object (&priv->constraints);
15000
15001   clutter_actor_queue_relayout (self);
15002
15003   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
15004 }
15005
15006 /**
15007  * clutter_actor_remove_constraint_by_name:
15008  * @self: a #ClutterActor
15009  * @name: the name of the constraint to remove
15010  *
15011  * Removes the #ClutterConstraint with the given name from the list
15012  * of constraints applied to @self
15013  *
15014  * Since: 1.4
15015  */
15016 void
15017 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15018                                          const gchar  *name)
15019 {
15020   ClutterActorPrivate *priv;
15021   ClutterActorMeta *meta;
15022
15023   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15024   g_return_if_fail (name != NULL);
15025
15026   priv = self->priv;
15027
15028   if (priv->constraints == NULL)
15029     return;
15030
15031   meta = _clutter_meta_group_get_meta (priv->constraints, name);
15032   if (meta == NULL)
15033     return;
15034
15035   _clutter_meta_group_remove_meta (priv->constraints, meta);
15036   clutter_actor_queue_relayout (self);
15037 }
15038
15039 /**
15040  * clutter_actor_get_constraints:
15041  * @self: a #ClutterActor
15042  *
15043  * Retrieves the list of constraints applied to @self
15044  *
15045  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15046  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15047  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15048  *   allocated by the returned #GList
15049  *
15050  * Since: 1.4
15051  */
15052 GList *
15053 clutter_actor_get_constraints (ClutterActor *self)
15054 {
15055   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15056
15057   if (self->priv->constraints == NULL)
15058     return NULL;
15059
15060   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15061 }
15062
15063 /**
15064  * clutter_actor_get_constraint:
15065  * @self: a #ClutterActor
15066  * @name: the name of the constraint to retrieve
15067  *
15068  * Retrieves the #ClutterConstraint with the given name in the list
15069  * of constraints applied to @self
15070  *
15071  * Return value: (transfer none): a #ClutterConstraint for the given
15072  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15073  *   actor and it should not be unreferenced directly
15074  *
15075  * Since: 1.4
15076  */
15077 ClutterConstraint *
15078 clutter_actor_get_constraint (ClutterActor *self,
15079                               const gchar  *name)
15080 {
15081   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15082   g_return_val_if_fail (name != NULL, NULL);
15083
15084   if (self->priv->constraints == NULL)
15085     return NULL;
15086
15087   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15088 }
15089
15090 /**
15091  * clutter_actor_clear_constraints:
15092  * @self: a #ClutterActor
15093  *
15094  * Clears the list of constraints applied to @self
15095  *
15096  * Since: 1.4
15097  */
15098 void
15099 clutter_actor_clear_constraints (ClutterActor *self)
15100 {
15101   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15102
15103   if (self->priv->constraints == NULL)
15104     return;
15105
15106   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15107
15108   clutter_actor_queue_relayout (self);
15109 }
15110
15111 /**
15112  * clutter_actor_set_clip_to_allocation:
15113  * @self: a #ClutterActor
15114  * @clip_set: %TRUE to apply a clip tracking the allocation
15115  *
15116  * Sets whether @self should be clipped to the same size as its
15117  * allocation
15118  *
15119  * Since: 1.4
15120  */
15121 void
15122 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15123                                       gboolean      clip_set)
15124 {
15125   ClutterActorPrivate *priv;
15126
15127   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15128
15129   clip_set = !!clip_set;
15130
15131   priv = self->priv;
15132
15133   if (priv->clip_to_allocation != clip_set)
15134     {
15135       priv->clip_to_allocation = clip_set;
15136
15137       clutter_actor_queue_redraw (self);
15138
15139       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15140     }
15141 }
15142
15143 /**
15144  * clutter_actor_get_clip_to_allocation:
15145  * @self: a #ClutterActor
15146  *
15147  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15148  *
15149  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15150  *
15151  * Since: 1.4
15152  */
15153 gboolean
15154 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15155 {
15156   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15157
15158   return self->priv->clip_to_allocation;
15159 }
15160
15161 /**
15162  * clutter_actor_add_effect:
15163  * @self: a #ClutterActor
15164  * @effect: a #ClutterEffect
15165  *
15166  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15167  *
15168  * The #ClutterActor will hold a reference on the @effect until either
15169  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15170  * called.
15171  *
15172  * Since: 1.4
15173  */
15174 void
15175 clutter_actor_add_effect (ClutterActor  *self,
15176                           ClutterEffect *effect)
15177 {
15178   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15179   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15180
15181   _clutter_actor_add_effect_internal (self, effect);
15182
15183   clutter_actor_queue_redraw (self);
15184
15185   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15186 }
15187
15188 /**
15189  * clutter_actor_add_effect_with_name:
15190  * @self: a #ClutterActor
15191  * @name: the name to set on the effect
15192  * @effect: a #ClutterEffect
15193  *
15194  * A convenience function for setting the name of a #ClutterEffect
15195  * while adding it to the list of effectss applied to @self
15196  *
15197  * This function is the logical equivalent of:
15198  *
15199  * |[
15200  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15201  *   clutter_actor_add_effect (self, effect);
15202  * ]|
15203  *
15204  * Since: 1.4
15205  */
15206 void
15207 clutter_actor_add_effect_with_name (ClutterActor  *self,
15208                                     const gchar   *name,
15209                                     ClutterEffect *effect)
15210 {
15211   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15212   g_return_if_fail (name != NULL);
15213   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15214
15215   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15216   clutter_actor_add_effect (self, effect);
15217 }
15218
15219 /**
15220  * clutter_actor_remove_effect:
15221  * @self: a #ClutterActor
15222  * @effect: a #ClutterEffect
15223  *
15224  * Removes @effect from the list of effects applied to @self
15225  *
15226  * The reference held by @self on the #ClutterEffect will be released
15227  *
15228  * Since: 1.4
15229  */
15230 void
15231 clutter_actor_remove_effect (ClutterActor  *self,
15232                              ClutterEffect *effect)
15233 {
15234   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15235   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15236
15237   _clutter_actor_remove_effect_internal (self, effect);
15238
15239   clutter_actor_queue_redraw (self);
15240
15241   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15242 }
15243
15244 /**
15245  * clutter_actor_remove_effect_by_name:
15246  * @self: a #ClutterActor
15247  * @name: the name of the effect to remove
15248  *
15249  * Removes the #ClutterEffect with the given name from the list
15250  * of effects applied to @self
15251  *
15252  * Since: 1.4
15253  */
15254 void
15255 clutter_actor_remove_effect_by_name (ClutterActor *self,
15256                                      const gchar  *name)
15257 {
15258   ClutterActorPrivate *priv;
15259   ClutterActorMeta *meta;
15260
15261   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15262   g_return_if_fail (name != NULL);
15263
15264   priv = self->priv;
15265
15266   if (priv->effects == NULL)
15267     return;
15268
15269   meta = _clutter_meta_group_get_meta (priv->effects, name);
15270   if (meta == NULL)
15271     return;
15272
15273   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15274 }
15275
15276 /**
15277  * clutter_actor_get_effects:
15278  * @self: a #ClutterActor
15279  *
15280  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15281  *
15282  * Return value: (transfer container) (element-type Clutter.Effect): a list
15283  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15284  *   list are owned by Clutter and they should not be freed. You should
15285  *   free the returned list using g_list_free() when done
15286  *
15287  * Since: 1.4
15288  */
15289 GList *
15290 clutter_actor_get_effects (ClutterActor *self)
15291 {
15292   ClutterActorPrivate *priv;
15293
15294   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15295
15296   priv = self->priv;
15297
15298   if (priv->effects == NULL)
15299     return NULL;
15300
15301   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15302 }
15303
15304 /**
15305  * clutter_actor_get_effect:
15306  * @self: a #ClutterActor
15307  * @name: the name of the effect to retrieve
15308  *
15309  * Retrieves the #ClutterEffect with the given name in the list
15310  * of effects applied to @self
15311  *
15312  * Return value: (transfer none): a #ClutterEffect for the given
15313  *   name, or %NULL. The returned #ClutterEffect is owned by the
15314  *   actor and it should not be unreferenced directly
15315  *
15316  * Since: 1.4
15317  */
15318 ClutterEffect *
15319 clutter_actor_get_effect (ClutterActor *self,
15320                           const gchar  *name)
15321 {
15322   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15323   g_return_val_if_fail (name != NULL, NULL);
15324
15325   if (self->priv->effects == NULL)
15326     return NULL;
15327
15328   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15329 }
15330
15331 /**
15332  * clutter_actor_clear_effects:
15333  * @self: a #ClutterActor
15334  *
15335  * Clears the list of effects applied to @self
15336  *
15337  * Since: 1.4
15338  */
15339 void
15340 clutter_actor_clear_effects (ClutterActor *self)
15341 {
15342   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15343
15344   if (self->priv->effects == NULL)
15345     return;
15346
15347   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15348
15349   clutter_actor_queue_redraw (self);
15350 }
15351
15352 /**
15353  * clutter_actor_has_key_focus:
15354  * @self: a #ClutterActor
15355  *
15356  * Checks whether @self is the #ClutterActor that has key focus
15357  *
15358  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15359  *
15360  * Since: 1.4
15361  */
15362 gboolean
15363 clutter_actor_has_key_focus (ClutterActor *self)
15364 {
15365   ClutterActor *stage;
15366
15367   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15368
15369   stage = _clutter_actor_get_stage_internal (self);
15370   if (stage == NULL)
15371     return FALSE;
15372
15373   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15374 }
15375
15376 static gboolean
15377 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15378                                       ClutterPaintVolume *pv)
15379 {
15380   ClutterActorPrivate *priv = self->priv;
15381
15382   /* Actors are only expected to report a valid paint volume
15383    * while they have a valid allocation. */
15384   if (G_UNLIKELY (priv->needs_allocation))
15385     {
15386       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15387                     "Actor needs allocation",
15388                     _clutter_actor_get_debug_name (self));
15389       return FALSE;
15390     }
15391
15392   /* Check if there are any handlers connected to the paint
15393    * signal. If there are then all bets are off for what the paint
15394    * volume for this actor might possibly be!
15395    *
15396    * XXX: It's expected that this is going to end up being quite a
15397    * costly check to have to do here, but we haven't come up with
15398    * another solution that can reliably catch paint signal handlers at
15399    * the right time to either avoid artefacts due to invalid stage
15400    * clipping or due to incorrect culling.
15401    *
15402    * Previously we checked in clutter_actor_paint(), but at that time
15403    * we may already be using a stage clip that could be derived from
15404    * an invalid paint-volume. We used to try and handle that by
15405    * queuing a follow up, unclipped, redraw but still the previous
15406    * checking wasn't enough to catch invalid volumes involved in
15407    * culling (considering that containers may derive their volume from
15408    * children that haven't yet been painted)
15409    *
15410    * Longer term, improved solutions could be:
15411    * - Disallow painting in the paint signal, only allow using it
15412    *   for tracking when paints happen. We can add another API that
15413    *   allows monkey patching the paint of arbitrary actors but in a
15414    *   more controlled way and that also supports modifying the
15415    *   paint-volume.
15416    * - If we could be notified somehow when signal handlers are
15417    *   connected we wouldn't have to poll for handlers like this.
15418    */
15419   if (g_signal_has_handler_pending (self,
15420                                     actor_signals[PAINT],
15421                                     0,
15422                                     TRUE))
15423     {
15424       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15425                     "Actor has \"paint\" signal handlers",
15426                     _clutter_actor_get_debug_name (self));
15427       return FALSE;
15428     }
15429
15430   _clutter_paint_volume_init_static (pv, self);
15431
15432   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15433     {
15434       clutter_paint_volume_free (pv);
15435       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15436                     "Actor failed to report a volume",
15437                     _clutter_actor_get_debug_name (self));
15438       return FALSE;
15439     }
15440
15441   /* since effects can modify the paint volume, we allow them to actually
15442    * do this by making get_paint_volume() "context sensitive"
15443    */
15444   if (priv->effects != NULL)
15445     {
15446       if (priv->current_effect != NULL)
15447         {
15448           const GList *effects, *l;
15449
15450           /* if we are being called from within the paint sequence of
15451            * an actor, get the paint volume up to the current effect
15452            */
15453           effects = _clutter_meta_group_peek_metas (priv->effects);
15454           for (l = effects;
15455                l != NULL || (l != NULL && l->data != priv->current_effect);
15456                l = l->next)
15457             {
15458               if (!_clutter_effect_get_paint_volume (l->data, pv))
15459                 {
15460                   clutter_paint_volume_free (pv);
15461                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15462                                 "Effect (%s) failed to report a volume",
15463                                 _clutter_actor_get_debug_name (self),
15464                                 _clutter_actor_meta_get_debug_name (l->data));
15465                   return FALSE;
15466                 }
15467             }
15468         }
15469       else
15470         {
15471           const GList *effects, *l;
15472
15473           /* otherwise, get the cumulative volume */
15474           effects = _clutter_meta_group_peek_metas (priv->effects);
15475           for (l = effects; l != NULL; l = l->next)
15476             if (!_clutter_effect_get_paint_volume (l->data, pv))
15477               {
15478                 clutter_paint_volume_free (pv);
15479                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15480                               "Effect (%s) failed to report a volume",
15481                               _clutter_actor_get_debug_name (self),
15482                               _clutter_actor_meta_get_debug_name (l->data));
15483                 return FALSE;
15484               }
15485         }
15486     }
15487
15488   return TRUE;
15489 }
15490
15491 /* The public clutter_actor_get_paint_volume API returns a const
15492  * pointer since we return a pointer directly to the cached
15493  * PaintVolume associated with the actor and don't want the user to
15494  * inadvertently modify it, but for internal uses we sometimes need
15495  * access to the same PaintVolume but need to apply some book-keeping
15496  * modifications to it so we don't want a const pointer.
15497  */
15498 static ClutterPaintVolume *
15499 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15500 {
15501   ClutterActorPrivate *priv;
15502
15503   priv = self->priv;
15504
15505   if (priv->paint_volume_valid)
15506     clutter_paint_volume_free (&priv->paint_volume);
15507
15508   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15509     {
15510       priv->paint_volume_valid = TRUE;
15511       return &priv->paint_volume;
15512     }
15513   else
15514     {
15515       priv->paint_volume_valid = FALSE;
15516       return NULL;
15517     }
15518 }
15519
15520 /**
15521  * clutter_actor_get_paint_volume:
15522  * @self: a #ClutterActor
15523  *
15524  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15525  * when a paint volume can't be determined.
15526  *
15527  * The paint volume is defined as the 3D space occupied by an actor
15528  * when being painted.
15529  *
15530  * This function will call the <function>get_paint_volume()</function>
15531  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15532  * should not usually care about overriding the default implementation,
15533  * unless they are, for instance: painting outside their allocation, or
15534  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15535  * 3D depth).
15536  *
15537  * <note>2D actors overriding <function>get_paint_volume()</function>
15538  * ensure their volume has a depth of 0. (This will be true so long as
15539  * you don't call clutter_paint_volume_set_depth().)</note>
15540  *
15541  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15542  *   or %NULL if no volume could be determined. The returned pointer
15543  *   is not guaranteed to be valid across multiple frames; if you want
15544  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15545  *
15546  * Since: 1.6
15547  */
15548 const ClutterPaintVolume *
15549 clutter_actor_get_paint_volume (ClutterActor *self)
15550 {
15551   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15552
15553   return _clutter_actor_get_paint_volume_mutable (self);
15554 }
15555
15556 /**
15557  * clutter_actor_get_transformed_paint_volume:
15558  * @self: a #ClutterActor
15559  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15560  *    (or %NULL for the stage)
15561  *
15562  * Retrieves the 3D paint volume of an actor like
15563  * clutter_actor_get_paint_volume() does (Please refer to the
15564  * documentation of clutter_actor_get_paint_volume() for more
15565  * details.) and it additionally transforms the paint volume into the
15566  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15567  * is passed for @relative_to_ancestor)
15568  *
15569  * This can be used by containers that base their paint volume on
15570  * the volume of their children. Such containers can query the
15571  * transformed paint volume of all of its children and union them
15572  * together using clutter_paint_volume_union().
15573  *
15574  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15575  *   or %NULL if no volume could be determined. The returned pointer is
15576  *   not guaranteed to be valid across multiple frames; if you wish to
15577  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15578  *
15579  * Since: 1.6
15580  */
15581 const ClutterPaintVolume *
15582 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15583                                             ClutterActor *relative_to_ancestor)
15584 {
15585   const ClutterPaintVolume *volume;
15586   ClutterActor *stage;
15587   ClutterPaintVolume *transformed_volume;
15588
15589   stage = _clutter_actor_get_stage_internal (self);
15590   if (G_UNLIKELY (stage == NULL))
15591     return NULL;
15592
15593   if (relative_to_ancestor == NULL)
15594     relative_to_ancestor = stage;
15595
15596   volume = clutter_actor_get_paint_volume (self);
15597   if (volume == NULL)
15598     return NULL;
15599
15600   transformed_volume =
15601     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15602
15603   _clutter_paint_volume_copy_static (volume, transformed_volume);
15604
15605   _clutter_paint_volume_transform_relative (transformed_volume,
15606                                             relative_to_ancestor);
15607
15608   return transformed_volume;
15609 }
15610
15611 /**
15612  * clutter_actor_get_paint_box:
15613  * @self: a #ClutterActor
15614  * @box: (out): return location for a #ClutterActorBox
15615  *
15616  * Retrieves the paint volume of the passed #ClutterActor, and
15617  * transforms it into a 2D bounding box in stage coordinates.
15618  *
15619  * This function is useful to determine the on screen area occupied by
15620  * the actor. The box is only an approximation and may often be
15621  * considerably larger due to the optimizations used to calculate the
15622  * box. The box is never smaller though, so it can reliably be used
15623  * for culling.
15624  *
15625  * There are times when a 2D paint box can't be determined, e.g.
15626  * because the actor isn't yet parented under a stage or because
15627  * the actor is unable to determine a paint volume.
15628  *
15629  * Return value: %TRUE if a 2D paint box could be determined, else
15630  * %FALSE.
15631  *
15632  * Since: 1.6
15633  */
15634 gboolean
15635 clutter_actor_get_paint_box (ClutterActor    *self,
15636                              ClutterActorBox *box)
15637 {
15638   ClutterActor *stage;
15639   ClutterPaintVolume *pv;
15640
15641   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15642   g_return_val_if_fail (box != NULL, FALSE);
15643
15644   stage = _clutter_actor_get_stage_internal (self);
15645   if (G_UNLIKELY (!stage))
15646     return FALSE;
15647
15648   pv = _clutter_actor_get_paint_volume_mutable (self);
15649   if (G_UNLIKELY (!pv))
15650     return FALSE;
15651
15652   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15653
15654   return TRUE;
15655 }
15656
15657 /**
15658  * clutter_actor_has_overlaps:
15659  * @self: A #ClutterActor
15660  *
15661  * Asks the actor's implementation whether it may contain overlapping
15662  * primitives.
15663  *
15664  * For example; Clutter may use this to determine whether the painting
15665  * should be redirected to an offscreen buffer to correctly implement
15666  * the opacity property.
15667  *
15668  * Custom actors can override the default response by implementing the
15669  * #ClutterActor <function>has_overlaps</function> virtual function. See
15670  * clutter_actor_set_offscreen_redirect() for more information.
15671  *
15672  * Return value: %TRUE if the actor may have overlapping primitives, and
15673  *   %FALSE otherwise
15674  *
15675  * Since: 1.8
15676  */
15677 gboolean
15678 clutter_actor_has_overlaps (ClutterActor *self)
15679 {
15680   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15681
15682   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15683 }
15684
15685 /**
15686  * clutter_actor_has_effects:
15687  * @self: A #ClutterActor
15688  *
15689  * Returns whether the actor has any effects applied.
15690  *
15691  * Return value: %TRUE if the actor has any effects,
15692  *   %FALSE otherwise
15693  *
15694  * Since: 1.10
15695  */
15696 gboolean
15697 clutter_actor_has_effects (ClutterActor *self)
15698 {
15699   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15700
15701   if (self->priv->effects == NULL)
15702     return FALSE;
15703
15704   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15705 }
15706
15707 /**
15708  * clutter_actor_has_constraints:
15709  * @self: A #ClutterActor
15710  *
15711  * Returns whether the actor has any constraints applied.
15712  *
15713  * Return value: %TRUE if the actor has any constraints,
15714  *   %FALSE otherwise
15715  *
15716  * Since: 1.10
15717  */
15718 gboolean
15719 clutter_actor_has_constraints (ClutterActor *self)
15720 {
15721   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15722
15723   return self->priv->constraints != NULL;
15724 }
15725
15726 /**
15727  * clutter_actor_has_actions:
15728  * @self: A #ClutterActor
15729  *
15730  * Returns whether the actor has any actions applied.
15731  *
15732  * Return value: %TRUE if the actor has any actions,
15733  *   %FALSE otherwise
15734  *
15735  * Since: 1.10
15736  */
15737 gboolean
15738 clutter_actor_has_actions (ClutterActor *self)
15739 {
15740   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15741
15742   return self->priv->actions != NULL;
15743 }
15744
15745 /**
15746  * clutter_actor_get_n_children:
15747  * @self: a #ClutterActor
15748  *
15749  * Retrieves the number of children of @self.
15750  *
15751  * Return value: the number of children of an actor
15752  *
15753  * Since: 1.10
15754  */
15755 gint
15756 clutter_actor_get_n_children (ClutterActor *self)
15757 {
15758   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15759
15760   return self->priv->n_children;
15761 }
15762
15763 /**
15764  * clutter_actor_get_child_at_index:
15765  * @self: a #ClutterActor
15766  * @index_: the position in the list of children
15767  *
15768  * Retrieves the actor at the given @index_ inside the list of
15769  * children of @self.
15770  *
15771  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15772  *
15773  * Since: 1.10
15774  */
15775 ClutterActor *
15776 clutter_actor_get_child_at_index (ClutterActor *self,
15777                                   gint          index_)
15778 {
15779   ClutterActor *iter;
15780   int i;
15781
15782   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15783   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15784
15785   for (iter = self->priv->first_child, i = 0;
15786        iter != NULL && i < index_;
15787        iter = iter->priv->next_sibling, i += 1)
15788     ;
15789
15790   return iter;
15791 }
15792
15793 /*< private >
15794  * _clutter_actor_foreach_child:
15795  * @actor: The actor whos children you want to iterate
15796  * @callback: The function to call for each child
15797  * @user_data: Private data to pass to @callback
15798  *
15799  * Calls a given @callback once for each child of the specified @actor and
15800  * passing the @user_data pointer each time.
15801  *
15802  * Return value: returns %TRUE if all children were iterated, else
15803  *    %FALSE if a callback broke out of iteration early.
15804  */
15805 gboolean
15806 _clutter_actor_foreach_child (ClutterActor           *self,
15807                               ClutterForeachCallback  callback,
15808                               gpointer                user_data)
15809 {
15810   ClutterActor *iter;
15811   gboolean cont;
15812
15813   if (self->priv->first_child == NULL)
15814     return TRUE;
15815
15816   cont = TRUE;
15817   iter = self->priv->first_child;
15818
15819   /* we use this form so that it's safe to change the children
15820    * list while iterating it
15821    */
15822   while (cont && iter != NULL)
15823     {
15824       ClutterActor *next = iter->priv->next_sibling;
15825
15826       cont = callback (iter, user_data);
15827
15828       iter = next;
15829     }
15830
15831   return cont;
15832 }
15833
15834 #if 0
15835 /* For debugging purposes this gives us a simple way to print out
15836  * the scenegraph e.g in gdb using:
15837  * [|
15838  *   _clutter_actor_traverse (stage,
15839  *                            0,
15840  *                            clutter_debug_print_actor_cb,
15841  *                            NULL,
15842  *                            NULL);
15843  * |]
15844  */
15845 static ClutterActorTraverseVisitFlags
15846 clutter_debug_print_actor_cb (ClutterActor *actor,
15847                               int depth,
15848                               void *user_data)
15849 {
15850   g_print ("%*s%s:%p\n",
15851            depth * 2, "",
15852            _clutter_actor_get_debug_name (actor),
15853            actor);
15854
15855   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15856 }
15857 #endif
15858
15859 static void
15860 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15861                                  ClutterTraverseCallback callback,
15862                                  gpointer                user_data)
15863 {
15864   GQueue *queue = g_queue_new ();
15865   ClutterActor dummy;
15866   int current_depth = 0;
15867
15868   g_queue_push_tail (queue, actor);
15869   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15870
15871   while ((actor = g_queue_pop_head (queue)))
15872     {
15873       ClutterActorTraverseVisitFlags flags;
15874
15875       if (actor == &dummy)
15876         {
15877           current_depth++;
15878           g_queue_push_tail (queue, &dummy);
15879           continue;
15880         }
15881
15882       flags = callback (actor, current_depth, user_data);
15883       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15884         break;
15885       else 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               g_queue_push_tail (queue, iter);
15894             }
15895         }
15896     }
15897
15898   g_queue_free (queue);
15899 }
15900
15901 static ClutterActorTraverseVisitFlags
15902 _clutter_actor_traverse_depth (ClutterActor           *actor,
15903                                ClutterTraverseCallback before_children_callback,
15904                                ClutterTraverseCallback after_children_callback,
15905                                int                     current_depth,
15906                                gpointer                user_data)
15907 {
15908   ClutterActorTraverseVisitFlags flags;
15909
15910   flags = before_children_callback (actor, current_depth, user_data);
15911   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15912     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15913
15914   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15915     {
15916       ClutterActor *iter;
15917
15918       for (iter = actor->priv->first_child;
15919            iter != NULL;
15920            iter = iter->priv->next_sibling)
15921         {
15922           flags = _clutter_actor_traverse_depth (iter,
15923                                                  before_children_callback,
15924                                                  after_children_callback,
15925                                                  current_depth + 1,
15926                                                  user_data);
15927
15928           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15929             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15930         }
15931     }
15932
15933   if (after_children_callback)
15934     return after_children_callback (actor, current_depth, user_data);
15935   else
15936     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15937 }
15938
15939 /* _clutter_actor_traverse:
15940  * @actor: The actor to start traversing the graph from
15941  * @flags: These flags may affect how the traversal is done
15942  * @before_children_callback: A function to call before visiting the
15943  *   children of the current actor.
15944  * @after_children_callback: A function to call after visiting the
15945  *   children of the current actor. (Ignored if
15946  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15947  * @user_data: The private data to pass to the callbacks
15948  *
15949  * Traverses the scenegraph starting at the specified @actor and
15950  * descending through all its children and its children's children.
15951  * For each actor traversed @before_children_callback and
15952  * @after_children_callback are called with the specified
15953  * @user_data, before and after visiting that actor's children.
15954  *
15955  * The callbacks can return flags that affect the ongoing traversal
15956  * such as by skipping over an actors children or bailing out of
15957  * any further traversing.
15958  */
15959 void
15960 _clutter_actor_traverse (ClutterActor              *actor,
15961                          ClutterActorTraverseFlags  flags,
15962                          ClutterTraverseCallback    before_children_callback,
15963                          ClutterTraverseCallback    after_children_callback,
15964                          gpointer                   user_data)
15965 {
15966   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15967     _clutter_actor_traverse_breadth (actor,
15968                                      before_children_callback,
15969                                      user_data);
15970   else /* DEPTH_FIRST */
15971     _clutter_actor_traverse_depth (actor,
15972                                    before_children_callback,
15973                                    after_children_callback,
15974                                    0, /* start depth */
15975                                    user_data);
15976 }
15977
15978 static void
15979 on_layout_manager_changed (ClutterLayoutManager *manager,
15980                            ClutterActor         *self)
15981 {
15982   clutter_actor_queue_relayout (self);
15983 }
15984
15985 /**
15986  * clutter_actor_set_layout_manager:
15987  * @self: a #ClutterActor
15988  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15989  *
15990  * Sets the #ClutterLayoutManager delegate object that will be used to
15991  * lay out the children of @self.
15992  *
15993  * The #ClutterActor will take a reference on the passed @manager which
15994  * will be released either when the layout manager is removed, or when
15995  * the actor is destroyed.
15996  *
15997  * Since: 1.10
15998  */
15999 void
16000 clutter_actor_set_layout_manager (ClutterActor         *self,
16001                                   ClutterLayoutManager *manager)
16002 {
16003   ClutterActorPrivate *priv;
16004
16005   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16006   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16007
16008   priv = self->priv;
16009
16010   if (priv->layout_manager != NULL)
16011     {
16012       g_signal_handlers_disconnect_by_func (priv->layout_manager,
16013                                             G_CALLBACK (on_layout_manager_changed),
16014                                             self);
16015       clutter_layout_manager_set_container (priv->layout_manager, NULL);
16016       g_clear_object (&priv->layout_manager);
16017     }
16018
16019   priv->layout_manager = manager;
16020
16021   if (priv->layout_manager != NULL)
16022     {
16023       g_object_ref_sink (priv->layout_manager);
16024       clutter_layout_manager_set_container (priv->layout_manager,
16025                                             CLUTTER_CONTAINER (self));
16026       g_signal_connect (priv->layout_manager, "layout-changed",
16027                         G_CALLBACK (on_layout_manager_changed),
16028                         self);
16029     }
16030
16031   clutter_actor_queue_relayout (self);
16032
16033   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16034 }
16035
16036 /**
16037  * clutter_actor_get_layout_manager:
16038  * @self: a #ClutterActor
16039  *
16040  * Retrieves the #ClutterLayoutManager used by @self.
16041  *
16042  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16043  *   or %NULL
16044  *
16045  * Since: 1.10
16046  */
16047 ClutterLayoutManager *
16048 clutter_actor_get_layout_manager (ClutterActor *self)
16049 {
16050   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16051
16052   return self->priv->layout_manager;
16053 }
16054
16055 static const ClutterLayoutInfo default_layout_info = {
16056   0.f,                          /* fixed-x */
16057   0.f,                          /* fixed-y */
16058   { 0, 0, 0, 0 },               /* margin */
16059   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
16060   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
16061   0.f, 0.f,                     /* min_width, natural_width */
16062   0.f, 0.f,                     /* natual_width, natural_height */
16063 };
16064
16065 static void
16066 layout_info_free (gpointer data)
16067 {
16068   if (G_LIKELY (data != NULL))
16069     g_slice_free (ClutterLayoutInfo, data);
16070 }
16071
16072 /*< private >
16073  * _clutter_actor_get_layout_info:
16074  * @self: a #ClutterActor
16075  *
16076  * Retrieves a pointer to the ClutterLayoutInfo structure.
16077  *
16078  * If the actor does not have a ClutterLayoutInfo associated to it, one
16079  * will be created and initialized to the default values.
16080  *
16081  * This function should be used for setters.
16082  *
16083  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16084  * instead.
16085  *
16086  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16087  */
16088 ClutterLayoutInfo *
16089 _clutter_actor_get_layout_info (ClutterActor *self)
16090 {
16091   ClutterLayoutInfo *retval;
16092
16093   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16094   if (retval == NULL)
16095     {
16096       retval = g_slice_new (ClutterLayoutInfo);
16097
16098       *retval = default_layout_info;
16099
16100       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16101                                retval,
16102                                layout_info_free);
16103     }
16104
16105   return retval;
16106 }
16107
16108 /*< private >
16109  * _clutter_actor_get_layout_info_or_defaults:
16110  * @self: a #ClutterActor
16111  *
16112  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16113  *
16114  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16115  * then the default structure will be returned.
16116  *
16117  * This function should only be used for getters.
16118  *
16119  * Return value: a const pointer to the ClutterLayoutInfo structure
16120  */
16121 const ClutterLayoutInfo *
16122 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16123 {
16124   const ClutterLayoutInfo *info;
16125
16126   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16127   if (info == NULL)
16128     return &default_layout_info;
16129
16130   return info;
16131 }
16132
16133 /**
16134  * clutter_actor_set_x_align:
16135  * @self: a #ClutterActor
16136  * @x_align: the horizontal alignment policy
16137  *
16138  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16139  * actor received extra horizontal space.
16140  *
16141  * See also the #ClutterActor:x-align property.
16142  *
16143  * Since: 1.10
16144  */
16145 void
16146 clutter_actor_set_x_align (ClutterActor      *self,
16147                            ClutterActorAlign  x_align)
16148 {
16149   ClutterLayoutInfo *info;
16150
16151   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16152
16153   info = _clutter_actor_get_layout_info (self);
16154
16155   if (info->x_align != x_align)
16156     {
16157       info->x_align = x_align;
16158
16159       clutter_actor_queue_relayout (self);
16160
16161       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16162     }
16163 }
16164
16165 /**
16166  * clutter_actor_get_x_align:
16167  * @self: a #ClutterActor
16168  *
16169  * Retrieves the horizontal alignment policy set using
16170  * clutter_actor_set_x_align().
16171  *
16172  * Return value: the horizontal alignment policy.
16173  *
16174  * Since: 1.10
16175  */
16176 ClutterActorAlign
16177 clutter_actor_get_x_align (ClutterActor *self)
16178 {
16179   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16180
16181   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16182 }
16183
16184 /**
16185  * clutter_actor_set_y_align:
16186  * @self: a #ClutterActor
16187  * @y_align: the vertical alignment policy
16188  *
16189  * Sets the vertical alignment policy of a #ClutterActor, in case the
16190  * actor received extra vertical space.
16191  *
16192  * See also the #ClutterActor:y-align property.
16193  *
16194  * Since: 1.10
16195  */
16196 void
16197 clutter_actor_set_y_align (ClutterActor      *self,
16198                            ClutterActorAlign  y_align)
16199 {
16200   ClutterLayoutInfo *info;
16201
16202   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16203
16204   info = _clutter_actor_get_layout_info (self);
16205
16206   if (info->y_align != y_align)
16207     {
16208       info->y_align = y_align;
16209
16210       clutter_actor_queue_relayout (self);
16211
16212       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16213     }
16214 }
16215
16216 /**
16217  * clutter_actor_get_y_align:
16218  * @self: a #ClutterActor
16219  *
16220  * Retrieves the vertical alignment policy set using
16221  * clutter_actor_set_y_align().
16222  *
16223  * Return value: the vertical alignment policy.
16224  *
16225  * Since: 1.10
16226  */
16227 ClutterActorAlign
16228 clutter_actor_get_y_align (ClutterActor *self)
16229 {
16230   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16231
16232   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16233 }
16234
16235
16236 /**
16237  * clutter_margin_new:
16238  *
16239  * Creates a new #ClutterMargin.
16240  *
16241  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16242  *   clutter_margin_free() to free the resources associated with it when
16243  *   done.
16244  *
16245  * Since: 1.10
16246  */
16247 ClutterMargin *
16248 clutter_margin_new (void)
16249 {
16250   return g_slice_new0 (ClutterMargin);
16251 }
16252
16253 /**
16254  * clutter_margin_copy:
16255  * @margin_: a #ClutterMargin
16256  *
16257  * Creates a new #ClutterMargin and copies the contents of @margin_ into
16258  * the newly created structure.
16259  *
16260  * Return value: (transfer full): a copy of the #ClutterMargin.
16261  *
16262  * Since: 1.10
16263  */
16264 ClutterMargin *
16265 clutter_margin_copy (const ClutterMargin *margin_)
16266 {
16267   if (G_LIKELY (margin_ != NULL))
16268     return g_slice_dup (ClutterMargin, margin_);
16269
16270   return NULL;
16271 }
16272
16273 /**
16274  * clutter_margin_free:
16275  * @margin_: a #ClutterMargin
16276  *
16277  * Frees the resources allocated by clutter_margin_new() and
16278  * clutter_margin_copy().
16279  *
16280  * Since: 1.10
16281  */
16282 void
16283 clutter_margin_free (ClutterMargin *margin_)
16284 {
16285   if (G_LIKELY (margin_ != NULL))
16286     g_slice_free (ClutterMargin, margin_);
16287 }
16288
16289 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16290                      clutter_margin_copy,
16291                      clutter_margin_free)
16292
16293 /**
16294  * clutter_actor_set_margin:
16295  * @self: a #ClutterActor
16296  * @margin: a #ClutterMargin
16297  *
16298  * Sets all the components of the margin of a #ClutterActor.
16299  *
16300  * Since: 1.10
16301  */
16302 void
16303 clutter_actor_set_margin (ClutterActor        *self,
16304                           const ClutterMargin *margin)
16305 {
16306   ClutterLayoutInfo *info;
16307   gboolean changed;
16308   GObject *obj;
16309
16310   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16311   g_return_if_fail (margin != NULL);
16312
16313   obj = G_OBJECT (self);
16314   changed = FALSE;
16315
16316   g_object_freeze_notify (obj);
16317
16318   info = _clutter_actor_get_layout_info (self);
16319
16320   if (info->margin.top != margin->top)
16321     {
16322       info->margin.top = margin->top;
16323       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16324       changed = TRUE;
16325     }
16326
16327   if (info->margin.right != margin->right)
16328     {
16329       info->margin.right = margin->right;
16330       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16331       changed = TRUE;
16332     }
16333
16334   if (info->margin.bottom != margin->bottom)
16335     {
16336       info->margin.bottom = margin->bottom;
16337       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16338       changed = TRUE;
16339     }
16340
16341   if (info->margin.left != margin->left)
16342     {
16343       info->margin.left = margin->left;
16344       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16345       changed = TRUE;
16346     }
16347
16348   if (changed)
16349     clutter_actor_queue_relayout (self);
16350
16351   g_object_thaw_notify (obj);
16352 }
16353
16354 /**
16355  * clutter_actor_get_margin:
16356  * @self: a #ClutterActor
16357  * @margin: (out caller-allocates): return location for a #ClutterMargin
16358  *
16359  * Retrieves all the components of the margin of a #ClutterActor.
16360  *
16361  * Since: 1.10
16362  */
16363 void
16364 clutter_actor_get_margin (ClutterActor  *self,
16365                           ClutterMargin *margin)
16366 {
16367   const ClutterLayoutInfo *info;
16368
16369   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16370   g_return_if_fail (margin != NULL);
16371
16372   info = _clutter_actor_get_layout_info_or_defaults (self);
16373
16374   *margin = info->margin;
16375 }
16376
16377 /**
16378  * clutter_actor_set_margin_top:
16379  * @self: a #ClutterActor
16380  * @margin: the top margin
16381  *
16382  * Sets the margin from the top of a #ClutterActor.
16383  *
16384  * Since: 1.10
16385  */
16386 void
16387 clutter_actor_set_margin_top (ClutterActor *self,
16388                               gfloat        margin)
16389 {
16390   ClutterLayoutInfo *info;
16391
16392   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16393   g_return_if_fail (margin >= 0.f);
16394
16395   info = _clutter_actor_get_layout_info (self);
16396
16397   if (info->margin.top == margin)
16398     return;
16399
16400   info->margin.top = margin;
16401
16402   clutter_actor_queue_relayout (self);
16403
16404   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16405 }
16406
16407 /**
16408  * clutter_actor_get_margin_top:
16409  * @self: a #ClutterActor
16410  *
16411  * Retrieves the top margin of a #ClutterActor.
16412  *
16413  * Return value: the top margin
16414  *
16415  * Since: 1.10
16416  */
16417 gfloat
16418 clutter_actor_get_margin_top (ClutterActor *self)
16419 {
16420   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16421
16422   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16423 }
16424
16425 /**
16426  * clutter_actor_set_margin_bottom:
16427  * @self: a #ClutterActor
16428  * @margin: the bottom margin
16429  *
16430  * Sets the margin from the bottom of a #ClutterActor.
16431  *
16432  * Since: 1.10
16433  */
16434 void
16435 clutter_actor_set_margin_bottom (ClutterActor *self,
16436                                  gfloat        margin)
16437 {
16438   ClutterLayoutInfo *info;
16439
16440   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16441   g_return_if_fail (margin >= 0.f);
16442
16443   info = _clutter_actor_get_layout_info (self);
16444
16445   if (info->margin.bottom == margin)
16446     return;
16447
16448   info->margin.bottom = margin;
16449
16450   clutter_actor_queue_relayout (self);
16451
16452   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16453 }
16454
16455 /**
16456  * clutter_actor_get_margin_bottom:
16457  * @self: a #ClutterActor
16458  *
16459  * Retrieves the bottom margin of a #ClutterActor.
16460  *
16461  * Return value: the bottom margin
16462  *
16463  * Since: 1.10
16464  */
16465 gfloat
16466 clutter_actor_get_margin_bottom (ClutterActor *self)
16467 {
16468   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16469
16470   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16471 }
16472
16473 /**
16474  * clutter_actor_set_margin_left:
16475  * @self: a #ClutterActor
16476  * @margin: the left margin
16477  *
16478  * Sets the margin from the left of a #ClutterActor.
16479  *
16480  * Since: 1.10
16481  */
16482 void
16483 clutter_actor_set_margin_left (ClutterActor *self,
16484                                gfloat        margin)
16485 {
16486   ClutterLayoutInfo *info;
16487
16488   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16489   g_return_if_fail (margin >= 0.f);
16490
16491   info = _clutter_actor_get_layout_info (self);
16492
16493   if (info->margin.left == margin)
16494     return;
16495
16496   info->margin.left = margin;
16497
16498   clutter_actor_queue_relayout (self);
16499
16500   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16501 }
16502
16503 /**
16504  * clutter_actor_get_margin_left:
16505  * @self: a #ClutterActor
16506  *
16507  * Retrieves the left margin of a #ClutterActor.
16508  *
16509  * Return value: the left margin
16510  *
16511  * Since: 1.10
16512  */
16513 gfloat
16514 clutter_actor_get_margin_left (ClutterActor *self)
16515 {
16516   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16517
16518   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16519 }
16520
16521 /**
16522  * clutter_actor_set_margin_right:
16523  * @self: a #ClutterActor
16524  * @margin: the right margin
16525  *
16526  * Sets the margin from the right of a #ClutterActor.
16527  *
16528  * Since: 1.10
16529  */
16530 void
16531 clutter_actor_set_margin_right (ClutterActor *self,
16532                                 gfloat        margin)
16533 {
16534   ClutterLayoutInfo *info;
16535
16536   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16537   g_return_if_fail (margin >= 0.f);
16538
16539   info = _clutter_actor_get_layout_info (self);
16540
16541   if (info->margin.right == margin)
16542     return;
16543
16544   info->margin.right = margin;
16545
16546   clutter_actor_queue_relayout (self);
16547
16548   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16549 }
16550
16551 /**
16552  * clutter_actor_get_margin_right:
16553  * @self: a #ClutterActor
16554  *
16555  * Retrieves the right margin of a #ClutterActor.
16556  *
16557  * Return value: the right margin
16558  *
16559  * Since: 1.10
16560  */
16561 gfloat
16562 clutter_actor_get_margin_right (ClutterActor *self)
16563 {
16564   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16565
16566   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16567 }
16568
16569 static inline void
16570 clutter_actor_set_background_color_internal (ClutterActor *self,
16571                                              const ClutterColor *color)
16572 {
16573   ClutterActorPrivate *priv = self->priv;
16574   GObject *obj;
16575
16576   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16577     return;
16578
16579   obj = G_OBJECT (self);
16580
16581   priv->bg_color = *color;
16582   priv->bg_color_set = TRUE;
16583
16584   clutter_actor_queue_redraw (self);
16585
16586   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16587   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16588 }
16589
16590 /**
16591  * clutter_actor_set_background_color:
16592  * @self: a #ClutterActor
16593  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16594  *  set color
16595  *
16596  * Sets the background color of a #ClutterActor.
16597  *
16598  * The background color will be used to cover the whole allocation of the
16599  * actor. The default background color of an actor is transparent.
16600  *
16601  * To check whether an actor has a background color, you can use the
16602  * #ClutterActor:background-color-set actor property.
16603  *
16604  * The #ClutterActor:background-color property is animatable.
16605  *
16606  * Since: 1.10
16607  */
16608 void
16609 clutter_actor_set_background_color (ClutterActor       *self,
16610                                     const ClutterColor *color)
16611 {
16612   ClutterActorPrivate *priv;
16613   GObject *obj;
16614   GParamSpec *bg_color_pspec;
16615
16616   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16617
16618   obj = G_OBJECT (self);
16619
16620   priv = self->priv;
16621
16622   if (color == NULL)
16623     {
16624       priv->bg_color_set = FALSE;
16625       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16626       clutter_actor_queue_redraw (self);
16627       return;
16628     }
16629
16630   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16631   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16632     {
16633       _clutter_actor_create_transition (self, bg_color_pspec,
16634                                         &priv->bg_color,
16635                                         color);
16636     }
16637   else
16638     _clutter_actor_update_transition (self, bg_color_pspec, color);
16639
16640   clutter_actor_queue_redraw (self);
16641 }
16642
16643 /**
16644  * clutter_actor_get_background_color:
16645  * @self: a #ClutterActor
16646  * @color: (out caller-allocates): return location for a #ClutterColor
16647  *
16648  * Retrieves the color set using clutter_actor_set_background_color().
16649  *
16650  * Since: 1.10
16651  */
16652 void
16653 clutter_actor_get_background_color (ClutterActor *self,
16654                                     ClutterColor *color)
16655 {
16656   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16657   g_return_if_fail (color != NULL);
16658
16659   *color = self->priv->bg_color;
16660 }
16661
16662 /**
16663  * clutter_actor_get_previous_sibling:
16664  * @self: a #ClutterActor
16665  *
16666  * Retrieves the sibling of @self that comes before it in the list
16667  * of children of @self's parent.
16668  *
16669  * The returned pointer is only valid until the scene graph changes; it
16670  * is not safe to modify the list of children of @self while iterating
16671  * it.
16672  *
16673  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16674  *
16675  * Since: 1.10
16676  */
16677 ClutterActor *
16678 clutter_actor_get_previous_sibling (ClutterActor *self)
16679 {
16680   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16681
16682   return self->priv->prev_sibling;
16683 }
16684
16685 /**
16686  * clutter_actor_get_next_sibling:
16687  * @self: a #ClutterActor
16688  *
16689  * Retrieves the sibling of @self that comes after it in the list
16690  * of children of @self's parent.
16691  *
16692  * The returned pointer is only valid until the scene graph changes; it
16693  * is not safe to modify the list of children of @self while iterating
16694  * it.
16695  *
16696  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16697  *
16698  * Since: 1.10
16699  */
16700 ClutterActor *
16701 clutter_actor_get_next_sibling (ClutterActor *self)
16702 {
16703   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16704
16705   return self->priv->next_sibling;
16706 }
16707
16708 /**
16709  * clutter_actor_get_first_child:
16710  * @self: a #ClutterActor
16711  *
16712  * Retrieves the first child of @self.
16713  *
16714  * The returned pointer is only valid until the scene graph changes; it
16715  * is not safe to modify the list of children of @self while iterating
16716  * it.
16717  *
16718  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16719  *
16720  * Since: 1.10
16721  */
16722 ClutterActor *
16723 clutter_actor_get_first_child (ClutterActor *self)
16724 {
16725   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16726
16727   return self->priv->first_child;
16728 }
16729
16730 /**
16731  * clutter_actor_get_last_child:
16732  * @self: a #ClutterActor
16733  *
16734  * Retrieves the last child of @self.
16735  *
16736  * The returned pointer is only valid until the scene graph changes; it
16737  * is not safe to modify the list of children of @self while iterating
16738  * it.
16739  *
16740  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16741  *
16742  * Since: 1.10
16743  */
16744 ClutterActor *
16745 clutter_actor_get_last_child (ClutterActor *self)
16746 {
16747   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16748
16749   return self->priv->last_child;
16750 }
16751
16752 /* easy way to have properly named fields instead of the dummy ones
16753  * we use in the public structure
16754  */
16755 typedef struct _RealActorIter
16756 {
16757   ClutterActor *root;           /* dummy1 */
16758   ClutterActor *current;        /* dummy2 */
16759   gpointer padding_1;           /* dummy3 */
16760   gint age;                     /* dummy4 */
16761   gpointer padding_2;           /* dummy5 */
16762 } RealActorIter;
16763
16764 /**
16765  * clutter_actor_iter_init:
16766  * @iter: a #ClutterActorIter
16767  * @root: a #ClutterActor
16768  *
16769  * Initializes a #ClutterActorIter, which can then be used to iterate
16770  * efficiently over a section of the scene graph, and associates it
16771  * with @root.
16772  *
16773  * Modifying the scene graph section that contains @root will invalidate
16774  * the iterator.
16775  *
16776  * |[
16777  *   ClutterActorIter iter;
16778  *   ClutterActor *child;
16779  *
16780  *   clutter_actor_iter_init (&iter, container);
16781  *   while (clutter_actor_iter_next (&iter, &child))
16782  *     {
16783  *       /&ast; do something with child &ast;/
16784  *     }
16785  * ]|
16786  *
16787  * Since: 1.10
16788  */
16789 void
16790 clutter_actor_iter_init (ClutterActorIter *iter,
16791                          ClutterActor     *root)
16792 {
16793   RealActorIter *ri = (RealActorIter *) iter;
16794
16795   g_return_if_fail (iter != NULL);
16796   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16797
16798   ri->root = root;
16799   ri->current = NULL;
16800   ri->age = root->priv->age;
16801 }
16802
16803 /**
16804  * clutter_actor_iter_next:
16805  * @iter: a #ClutterActorIter
16806  * @child: (out): return location for a #ClutterActor
16807  *
16808  * Advances the @iter and retrieves the next child of the root #ClutterActor
16809  * that was used to initialize the #ClutterActorIterator.
16810  *
16811  * If the iterator can advance, this function returns %TRUE and sets the
16812  * @child argument.
16813  *
16814  * If the iterator cannot advance, this function returns %FALSE, and
16815  * the contents of @child are undefined.
16816  *
16817  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16818  *
16819  * Since: 1.10
16820  */
16821 gboolean
16822 clutter_actor_iter_next (ClutterActorIter  *iter,
16823                          ClutterActor     **child)
16824 {
16825   RealActorIter *ri = (RealActorIter *) iter;
16826
16827   g_return_val_if_fail (iter != NULL, FALSE);
16828   g_return_val_if_fail (ri->root != NULL, FALSE);
16829 #ifndef G_DISABLE_ASSERT
16830   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16831 #endif
16832
16833   if (ri->current == NULL)
16834     ri->current = ri->root->priv->first_child;
16835   else
16836     ri->current = ri->current->priv->next_sibling;
16837
16838   if (child != NULL)
16839     *child = ri->current;
16840
16841   return ri->current != NULL;
16842 }
16843
16844 /**
16845  * clutter_actor_iter_prev:
16846  * @iter: a #ClutterActorIter
16847  * @child: (out): return location for a #ClutterActor
16848  *
16849  * Advances the @iter and retrieves the previous child of the root
16850  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16851  *
16852  * If the iterator can advance, this function returns %TRUE and sets the
16853  * @child argument.
16854  *
16855  * If the iterator cannot advance, this function returns %FALSE, and
16856  * the contents of @child are undefined.
16857  *
16858  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16859  *
16860  * Since: 1.10
16861  */
16862 gboolean
16863 clutter_actor_iter_prev (ClutterActorIter  *iter,
16864                          ClutterActor     **child)
16865 {
16866   RealActorIter *ri = (RealActorIter *) iter;
16867
16868   g_return_val_if_fail (iter != NULL, FALSE);
16869   g_return_val_if_fail (ri->root != NULL, FALSE);
16870 #ifndef G_DISABLE_ASSERT
16871   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16872 #endif
16873
16874   if (ri->current == NULL)
16875     ri->current = ri->root->priv->last_child;
16876   else
16877     ri->current = ri->current->priv->prev_sibling;
16878
16879   if (child != NULL)
16880     *child = ri->current;
16881
16882   return ri->current != NULL;
16883 }
16884
16885 /**
16886  * clutter_actor_iter_remove:
16887  * @iter: a #ClutterActorIter
16888  *
16889  * Safely removes the #ClutterActor currently pointer to by the iterator
16890  * from its parent.
16891  *
16892  * This function can only be called after clutter_actor_iter_next() or
16893  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16894  * than once for the same actor.
16895  *
16896  * This function will call clutter_actor_remove_child() internally.
16897  *
16898  * Since: 1.10
16899  */
16900 void
16901 clutter_actor_iter_remove (ClutterActorIter *iter)
16902 {
16903   RealActorIter *ri = (RealActorIter *) iter;
16904   ClutterActor *cur;
16905
16906   g_return_if_fail (iter != NULL);
16907   g_return_if_fail (ri->root != NULL);
16908 #ifndef G_DISABLE_ASSERT
16909   g_return_if_fail (ri->age == ri->root->priv->age);
16910 #endif
16911   g_return_if_fail (ri->current != NULL);
16912
16913   cur = ri->current;
16914
16915   if (cur != NULL)
16916     {
16917       ri->current = cur->priv->prev_sibling;
16918
16919       clutter_actor_remove_child_internal (ri->root, cur,
16920                                            REMOVE_CHILD_DEFAULT_FLAGS);
16921
16922       ri->age += 1;
16923     }
16924 }
16925
16926 /**
16927  * clutter_actor_iter_destroy:
16928  * @iter: a #ClutterActorIter
16929  *
16930  * Safely destroys the #ClutterActor currently pointer to by the iterator
16931  * from its parent.
16932  *
16933  * This function can only be called after clutter_actor_iter_next() or
16934  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16935  * than once for the same actor.
16936  *
16937  * This function will call clutter_actor_destroy() internally.
16938  *
16939  * Since: 1.10
16940  */
16941 void
16942 clutter_actor_iter_destroy (ClutterActorIter *iter)
16943 {
16944   RealActorIter *ri = (RealActorIter *) iter;
16945   ClutterActor *cur;
16946
16947   g_return_if_fail (iter != NULL);
16948   g_return_if_fail (ri->root != NULL);
16949 #ifndef G_DISABLE_ASSERT
16950   g_return_if_fail (ri->age == ri->root->priv->age);
16951 #endif
16952   g_return_if_fail (ri->current != NULL);
16953
16954   cur = ri->current;
16955
16956   if (cur != NULL)
16957     {
16958       ri->current = cur->priv->prev_sibling;
16959
16960       clutter_actor_destroy (cur);
16961
16962       ri->age += 1;
16963     }
16964 }
16965
16966 static const ClutterAnimationInfo default_animation_info = {
16967   NULL,         /* transitions */
16968   NULL,         /* states */
16969   NULL,         /* cur_state */
16970 };
16971
16972 static void
16973 clutter_animation_info_free (gpointer data)
16974 {
16975   if (data != NULL)
16976     {
16977       ClutterAnimationInfo *info = data;
16978
16979       if (info->transitions != NULL)
16980         g_hash_table_unref (info->transitions);
16981
16982       if (info->states != NULL)
16983         g_array_unref (info->states);
16984
16985       g_slice_free (ClutterAnimationInfo, info);
16986     }
16987 }
16988
16989 const ClutterAnimationInfo *
16990 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16991 {
16992   const ClutterAnimationInfo *res;
16993   GObject *obj = G_OBJECT (self);
16994
16995   res = g_object_get_qdata (obj, quark_actor_animation_info);
16996   if (res != NULL)
16997     return res;
16998
16999   return &default_animation_info;
17000 }
17001
17002 ClutterAnimationInfo *
17003 _clutter_actor_get_animation_info (ClutterActor *self)
17004 {
17005   GObject *obj = G_OBJECT (self);
17006   ClutterAnimationInfo *res;
17007
17008   res = g_object_get_qdata (obj, quark_actor_animation_info);
17009   if (res == NULL)
17010     {
17011       res = g_slice_new (ClutterAnimationInfo);
17012
17013       *res = default_animation_info;
17014
17015       g_object_set_qdata_full (obj, quark_actor_animation_info,
17016                                res,
17017                                clutter_animation_info_free);
17018     }
17019
17020   return res;
17021 }
17022
17023 ClutterTransition *
17024 _clutter_actor_get_transition (ClutterActor *actor,
17025                                GParamSpec   *pspec)
17026 {
17027   const ClutterAnimationInfo *info;
17028
17029   info = _clutter_actor_get_animation_info_or_defaults (actor);
17030
17031   if (info->transitions == NULL)
17032     return NULL;
17033
17034   return g_hash_table_lookup (info->transitions, pspec->name);
17035 }
17036
17037 typedef struct _TransitionClosure
17038 {
17039   ClutterActor *actor;
17040   ClutterTransition *transition;
17041   gchar *name;
17042   gulong completed_id;
17043 } TransitionClosure;
17044
17045 static void
17046 transition_closure_free (gpointer data)
17047 {
17048   if (G_LIKELY (data != NULL))
17049     {
17050       TransitionClosure *clos = data;
17051       ClutterTimeline *timeline;
17052
17053       timeline = CLUTTER_TIMELINE (clos->transition);
17054
17055       if (clutter_timeline_is_playing (timeline))
17056         clutter_timeline_stop (timeline);
17057
17058       g_signal_handler_disconnect (clos->transition, clos->completed_id);
17059
17060       g_object_unref (clos->transition);
17061       g_free (clos->name);
17062
17063       g_slice_free (TransitionClosure, clos);
17064     }
17065 }
17066
17067 static void
17068 on_transition_completed (ClutterTransition *transition,
17069                          TransitionClosure *clos)
17070 {
17071   ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
17072   ClutterActor *actor = clos->actor;
17073   ClutterAnimationInfo *info;
17074   gint n_repeats, cur_repeat;
17075
17076   info = _clutter_actor_get_animation_info (actor);
17077
17078   /* reset the caches used by animations */
17079   clutter_actor_store_content_box (actor, NULL);
17080
17081   /* ensure that we remove the transition only at the end
17082    * of its run; we emit ::completed for every repeat
17083    */
17084   n_repeats = clutter_timeline_get_repeat_count (timeline);
17085   cur_repeat = clutter_timeline_get_current_repeat (timeline);
17086
17087   if (cur_repeat == n_repeats)
17088     {
17089       if (clutter_transition_get_remove_on_complete (transition))
17090         {
17091           /* we take a reference here because removing the closure
17092            * will release the reference on the transition, and we
17093            * want the transition to survive the signal emission;
17094            * the master clock will release the last reference at
17095            * the end of the frame processing.
17096            */
17097           g_object_ref (transition);
17098           g_hash_table_remove (info->transitions, clos->name);
17099         }
17100     }
17101
17102   /* if it's the last transition then we clean up */
17103   if (g_hash_table_size (info->transitions) == 0)
17104     {
17105       g_hash_table_unref (info->transitions);
17106       info->transitions = NULL;
17107
17108       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17109                     _clutter_actor_get_debug_name (actor));
17110
17111       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17112     }
17113 }
17114
17115 void
17116 _clutter_actor_update_transition (ClutterActor *actor,
17117                                   GParamSpec   *pspec,
17118                                   ...)
17119 {
17120   TransitionClosure *clos;
17121   ClutterTimeline *timeline;
17122   ClutterInterval *interval;
17123   const ClutterAnimationInfo *info;
17124   va_list var_args;
17125   GType ptype;
17126   GValue initial = G_VALUE_INIT;
17127   GValue final = G_VALUE_INIT;
17128   char *error = NULL;
17129
17130   info = _clutter_actor_get_animation_info_or_defaults (actor);
17131
17132   if (info->transitions == NULL)
17133     return;
17134
17135   clos = g_hash_table_lookup (info->transitions, pspec->name);
17136   if (clos == NULL)
17137     return;
17138
17139   timeline = CLUTTER_TIMELINE (clos->transition);
17140
17141   va_start (var_args, pspec);
17142
17143   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17144
17145   g_value_init (&initial, ptype);
17146   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17147                                         pspec->name,
17148                                         &initial);
17149
17150   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17151   if (error != NULL)
17152     {
17153       g_critical ("%s: %s", G_STRLOC, error);
17154       g_free (error);
17155       goto out;
17156     }
17157
17158   interval = clutter_transition_get_interval (clos->transition);
17159   clutter_interval_set_initial_value (interval, &initial);
17160   clutter_interval_set_final_value (interval, &final);
17161
17162   /* if we're updating with an easing duration of zero milliseconds,
17163    * we just jump the timeline to the end and let it run its course
17164    */
17165   if (info->cur_state != NULL &&
17166       info->cur_state->easing_duration != 0)
17167     {
17168       guint cur_duration = clutter_timeline_get_duration (timeline);
17169       ClutterAnimationMode cur_mode =
17170         clutter_timeline_get_progress_mode (timeline);
17171
17172       if (cur_duration != info->cur_state->easing_duration)
17173         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17174
17175       if (cur_mode != info->cur_state->easing_mode)
17176         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17177
17178       clutter_timeline_rewind (timeline);
17179     }
17180   else
17181     {
17182       guint duration = clutter_timeline_get_duration (timeline);
17183
17184       clutter_timeline_advance (timeline, duration);
17185     }
17186
17187 out:
17188   g_value_unset (&initial);
17189   g_value_unset (&final);
17190
17191   va_end (var_args);
17192 }
17193
17194 /*< private >*
17195  * _clutter_actor_create_transition:
17196  * @actor: a #ClutterActor
17197  * @pspec: the property used for the transition
17198  * @...: initial and final state
17199  *
17200  * Creates a #ClutterTransition for the property represented by @pspec.
17201  *
17202  * Return value: a #ClutterTransition
17203  */
17204 ClutterTransition *
17205 _clutter_actor_create_transition (ClutterActor *actor,
17206                                   GParamSpec   *pspec,
17207                                   ...)
17208 {
17209   ClutterAnimationInfo *info;
17210   ClutterTransition *res = NULL;
17211   gboolean call_restore = FALSE;
17212   TransitionClosure *clos;
17213   va_list var_args;
17214
17215   info = _clutter_actor_get_animation_info (actor);
17216
17217   /* XXX - this will go away in 2.0
17218    *
17219    * if no state has been pushed, we assume that the easing state is
17220    * in "compatibility mode": all transitions have a duration of 0
17221    * msecs, which means that they happen immediately. in Clutter 2.0
17222    * this will turn into a g_assert(info->states != NULL), as every
17223    * actor will start with a predefined easing state
17224    */
17225   if (info->states == NULL)
17226     {
17227       clutter_actor_save_easing_state (actor);
17228       clutter_actor_set_easing_duration (actor, 0);
17229       call_restore = TRUE;
17230     }
17231
17232   if (info->transitions == NULL)
17233     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17234                                                NULL,
17235                                                transition_closure_free);
17236
17237   va_start (var_args, pspec);
17238
17239   clos = g_hash_table_lookup (info->transitions, pspec->name);
17240   if (clos == NULL)
17241     {
17242       ClutterInterval *interval;
17243       GValue initial = G_VALUE_INIT;
17244       GValue final = G_VALUE_INIT;
17245       GType ptype;
17246       char *error;
17247
17248       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17249
17250       G_VALUE_COLLECT_INIT (&initial, ptype,
17251                             var_args, 0,
17252                             &error);
17253       if (error != NULL)
17254         {
17255           g_critical ("%s: %s", G_STRLOC, error);
17256           g_free (error);
17257           goto out;
17258         }
17259
17260       G_VALUE_COLLECT_INIT (&final, ptype,
17261                             var_args, 0,
17262                             &error);
17263
17264       if (error != NULL)
17265         {
17266           g_critical ("%s: %s", G_STRLOC, error);
17267           g_value_unset (&initial);
17268           g_free (error);
17269           goto out;
17270         }
17271
17272       /* if the current easing state has a duration of 0, then we don't
17273        * bother to create the transition, and we just set the final value
17274        * directly on the actor; we don't go through the Animatable
17275        * interface because we know we got here through an animatable
17276        * property.
17277        */
17278       if (info->cur_state->easing_duration == 0)
17279         {
17280           clutter_actor_set_animatable_property (actor,
17281                                                  pspec->param_id,
17282                                                  &final,
17283                                                  pspec);
17284           g_value_unset (&initial);
17285           g_value_unset (&final);
17286
17287           goto out;
17288         }
17289
17290       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17291
17292       g_value_unset (&initial);
17293       g_value_unset (&final);
17294
17295       res = clutter_property_transition_new (pspec->name);
17296
17297       clutter_transition_set_interval (res, interval);
17298       clutter_transition_set_remove_on_complete (res, TRUE);
17299
17300       /* this will start the transition as well */
17301       clutter_actor_add_transition (actor, pspec->name, res);
17302
17303       /* the actor now owns the transition */
17304       g_object_unref (res);
17305     }
17306   else
17307     res = clos->transition;
17308
17309 out:
17310   if (call_restore)
17311     clutter_actor_restore_easing_state (actor);
17312
17313   va_end (var_args);
17314
17315   return res;
17316 }
17317
17318 /**
17319  * clutter_actor_add_transition:
17320  * @self: a #ClutterActor
17321  * @name: the name of the transition to add
17322  * @transition: the #ClutterTransition to add
17323  *
17324  * Adds a @transition to the #ClutterActor's list of animations.
17325  *
17326  * The @name string is a per-actor unique identifier of the @transition: only
17327  * one #ClutterTransition can be associated to the specified @name.
17328  *
17329  * The @transition will be given the easing duration, mode, and delay
17330  * associated to the actor's current easing state; it is possible to modify
17331  * these values after calling clutter_actor_add_transition().
17332  *
17333  * The @transition will be started once added.
17334  *
17335  * This function will take a reference on the @transition.
17336  *
17337  * This function is usually called implicitly when modifying an animatable
17338  * property.
17339  *
17340  * Since: 1.10
17341  */
17342 void
17343 clutter_actor_add_transition (ClutterActor      *self,
17344                               const char        *name,
17345                               ClutterTransition *transition)
17346 {
17347   ClutterTimeline *timeline;
17348   TransitionClosure *clos;
17349   ClutterAnimationInfo *info;
17350
17351   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17352   g_return_if_fail (name != NULL);
17353   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17354
17355   info = _clutter_actor_get_animation_info (self);
17356
17357   if (info->cur_state == NULL)
17358     {
17359       g_warning ("No easing state is defined for the actor '%s'; you "
17360                  "must call clutter_actor_save_easing_state() before "
17361                  "calling clutter_actor_add_transition().",
17362                  _clutter_actor_get_debug_name (self));
17363       return;
17364     }
17365
17366   if (info->transitions == NULL)
17367     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17368                                                NULL,
17369                                                transition_closure_free);
17370
17371   if (g_hash_table_lookup (info->transitions, name) != NULL)
17372     {
17373       g_warning ("A transition with name '%s' already exists for "
17374                  "the actor '%s'",
17375                  name,
17376                  _clutter_actor_get_debug_name (self));
17377       return;
17378     }
17379
17380   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17381
17382   timeline = CLUTTER_TIMELINE (transition);
17383
17384   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17385   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17386   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17387
17388   clos = g_slice_new (TransitionClosure);
17389   clos->actor = self;
17390   clos->transition = g_object_ref (transition);
17391   clos->name = g_strdup (name);
17392   clos->completed_id = g_signal_connect (timeline, "completed",
17393                                          G_CALLBACK (on_transition_completed),
17394                                          clos);
17395
17396   CLUTTER_NOTE (ANIMATION,
17397                 "Adding transition '%s' [%p] to actor '%s'",
17398                 clos->name,
17399                 clos->transition,
17400                 _clutter_actor_get_debug_name (self));
17401
17402   g_hash_table_insert (info->transitions, clos->name, clos);
17403   clutter_timeline_start (timeline);
17404 }
17405
17406 /**
17407  * clutter_actor_remove_transition:
17408  * @self: a #ClutterActor
17409  * @name: the name of the transition to remove
17410  *
17411  * Removes the transition stored inside a #ClutterActor using @name
17412  * identifier.
17413  *
17414  * If the transition is currently in progress, it will be stopped.
17415  *
17416  * This function releases the reference acquired when the transition
17417  * was added to the #ClutterActor.
17418  *
17419  * Since: 1.10
17420  */
17421 void
17422 clutter_actor_remove_transition (ClutterActor *self,
17423                                  const char   *name)
17424 {
17425   const ClutterAnimationInfo *info;
17426
17427   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17428   g_return_if_fail (name != NULL);
17429
17430   info = _clutter_actor_get_animation_info_or_defaults (self);
17431
17432   if (info->transitions == NULL)
17433     return;
17434
17435   g_hash_table_remove (info->transitions, name);
17436 }
17437
17438 /**
17439  * clutter_actor_remove_all_transitions:
17440  * @self: a #ClutterActor
17441  *
17442  * Removes all transitions associated to @self.
17443  *
17444  * Since: 1.10
17445  */
17446 void
17447 clutter_actor_remove_all_transitions (ClutterActor *self)
17448 {
17449   const ClutterAnimationInfo *info;
17450
17451   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17452
17453   info = _clutter_actor_get_animation_info_or_defaults (self);
17454   if (info->transitions == NULL)
17455     return;
17456
17457   g_hash_table_remove_all (info->transitions);
17458 }
17459
17460 /**
17461  * clutter_actor_set_easing_duration:
17462  * @self: a #ClutterActor
17463  * @msecs: the duration of the easing, or %NULL
17464  *
17465  * Sets the duration of the tweening for animatable properties
17466  * of @self for the current easing state.
17467  *
17468  * Since: 1.10
17469  */
17470 void
17471 clutter_actor_set_easing_duration (ClutterActor *self,
17472                                    guint         msecs)
17473 {
17474   ClutterAnimationInfo *info;
17475
17476   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17477
17478   info = _clutter_actor_get_animation_info (self);
17479
17480   if (info->cur_state == NULL)
17481     {
17482       g_warning ("You must call clutter_actor_save_easing_state() prior "
17483                  "to calling clutter_actor_set_easing_duration().");
17484       return;
17485     }
17486
17487   if (info->cur_state->easing_duration != msecs)
17488     info->cur_state->easing_duration = msecs;
17489 }
17490
17491 /**
17492  * clutter_actor_get_easing_duration:
17493  * @self: a #ClutterActor
17494  *
17495  * Retrieves the duration of the tweening for animatable
17496  * properties of @self for the current easing state.
17497  *
17498  * Return value: the duration of the tweening, in milliseconds
17499  *
17500  * Since: 1.10
17501  */
17502 guint
17503 clutter_actor_get_easing_duration (ClutterActor *self)
17504 {
17505   const ClutterAnimationInfo *info;
17506
17507   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17508
17509   info = _clutter_actor_get_animation_info_or_defaults (self);
17510
17511   if (info->cur_state != NULL)
17512     return info->cur_state->easing_duration;
17513
17514   return 0;
17515 }
17516
17517 /**
17518  * clutter_actor_set_easing_mode:
17519  * @self: a #ClutterActor
17520  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17521  *
17522  * Sets the easing mode for the tweening of animatable properties
17523  * of @self.
17524  *
17525  * Since: 1.10
17526  */
17527 void
17528 clutter_actor_set_easing_mode (ClutterActor         *self,
17529                                ClutterAnimationMode  mode)
17530 {
17531   ClutterAnimationInfo *info;
17532
17533   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17534   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17535   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17536
17537   info = _clutter_actor_get_animation_info (self);
17538
17539   if (info->cur_state == NULL)
17540     {
17541       g_warning ("You must call clutter_actor_save_easing_state() prior "
17542                  "to calling clutter_actor_set_easing_mode().");
17543       return;
17544     }
17545
17546   if (info->cur_state->easing_mode != mode)
17547     info->cur_state->easing_mode = mode;
17548 }
17549
17550 /**
17551  * clutter_actor_get_easing_mode:
17552  * @self: a #ClutterActor
17553  *
17554  * Retrieves the easing mode for the tweening of animatable properties
17555  * of @self for the current easing state.
17556  *
17557  * Return value: an easing mode
17558  *
17559  * Since: 1.10
17560  */
17561 ClutterAnimationMode
17562 clutter_actor_get_easing_mode (ClutterActor *self)
17563 {
17564   const ClutterAnimationInfo *info;
17565
17566   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17567
17568   info = _clutter_actor_get_animation_info_or_defaults (self);
17569
17570   if (info->cur_state != NULL)
17571     return info->cur_state->easing_mode;
17572
17573   return CLUTTER_EASE_OUT_CUBIC;
17574 }
17575
17576 /**
17577  * clutter_actor_set_easing_delay:
17578  * @self: a #ClutterActor
17579  * @msecs: the delay before the start of the tweening, in milliseconds
17580  *
17581  * Sets the delay that should be applied before tweening animatable
17582  * properties.
17583  *
17584  * Since: 1.10
17585  */
17586 void
17587 clutter_actor_set_easing_delay (ClutterActor *self,
17588                                 guint         msecs)
17589 {
17590   ClutterAnimationInfo *info;
17591
17592   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17593
17594   info = _clutter_actor_get_animation_info (self);
17595
17596   if (info->cur_state == NULL)
17597     {
17598       g_warning ("You must call clutter_actor_save_easing_state() prior "
17599                  "to calling clutter_actor_set_easing_delay().");
17600       return;
17601     }
17602
17603   if (info->cur_state->easing_delay != msecs)
17604     info->cur_state->easing_delay = msecs;
17605 }
17606
17607 /**
17608  * clutter_actor_get_easing_delay:
17609  * @self: a #ClutterActor
17610  *
17611  * Retrieves the delay that should be applied when tweening animatable
17612  * properties.
17613  *
17614  * Return value: a delay, in milliseconds
17615  *
17616  * Since: 1.10
17617  */
17618 guint
17619 clutter_actor_get_easing_delay (ClutterActor *self)
17620 {
17621   const ClutterAnimationInfo *info;
17622
17623   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17624
17625   info = _clutter_actor_get_animation_info_or_defaults (self);
17626
17627   if (info->cur_state != NULL)
17628     return info->cur_state->easing_delay;
17629
17630   return 0;
17631 }
17632
17633 /**
17634  * clutter_actor_get_transition:
17635  * @self: a #ClutterActor
17636  * @name: the name of the transition
17637  *
17638  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17639  * transition @name.
17640  *
17641  * Transitions created for animatable properties use the name of the
17642  * property itself, for instance the code below:
17643  *
17644  * |[
17645  *   clutter_actor_set_easing_duration (actor, 1000);
17646  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17647  *
17648  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17649  *   g_signal_connect (transition, "completed",
17650  *                     G_CALLBACK (on_transition_complete),
17651  *                     actor);
17652  * ]|
17653  *
17654  * will call the <function>on_transition_complete</function> callback when
17655  * the transition is complete.
17656  *
17657  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17658  *   was found to match the passed name; the returned instance is owned
17659  *   by Clutter and it should not be freed
17660  *
17661  * Since: 1.10
17662  */
17663 ClutterTransition *
17664 clutter_actor_get_transition (ClutterActor *self,
17665                               const char   *name)
17666 {
17667   TransitionClosure *clos;
17668   const ClutterAnimationInfo *info;
17669
17670   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17671   g_return_val_if_fail (name != NULL, NULL);
17672
17673   info = _clutter_actor_get_animation_info_or_defaults (self);
17674   if (info->transitions == NULL)
17675     return NULL;
17676
17677   clos = g_hash_table_lookup (info->transitions, name);
17678   if (clos == NULL)
17679     return NULL;
17680
17681   return clos->transition;
17682 }
17683
17684 /**
17685  * clutter_actor_save_easing_state:
17686  * @self: a #ClutterActor
17687  *
17688  * Saves the current easing state for animatable properties, and creates
17689  * a new state with the default values for easing mode and duration.
17690  *
17691  * Since: 1.10
17692  */
17693 void
17694 clutter_actor_save_easing_state (ClutterActor *self)
17695 {
17696   ClutterAnimationInfo *info;
17697   AState new_state;
17698
17699   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17700
17701   info = _clutter_actor_get_animation_info (self);
17702
17703   if (info->states == NULL)
17704     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17705
17706   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17707   new_state.easing_duration = 250;
17708   new_state.easing_delay = 0;
17709
17710   g_array_append_val (info->states, new_state);
17711
17712   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17713 }
17714
17715 /**
17716  * clutter_actor_restore_easing_state:
17717  * @self: a #ClutterActor
17718  *
17719  * Restores the easing state as it was prior to a call to
17720  * clutter_actor_save_easing_state().
17721  *
17722  * Since: 1.10
17723  */
17724 void
17725 clutter_actor_restore_easing_state (ClutterActor *self)
17726 {
17727   ClutterAnimationInfo *info;
17728
17729   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17730
17731   info = _clutter_actor_get_animation_info (self);
17732
17733   if (info->states == NULL)
17734     {
17735       g_critical ("The function clutter_actor_restore_easing_state() has "
17736                   "called without a previous call to "
17737                   "clutter_actor_save_easing_state().");
17738       return;
17739     }
17740
17741   g_array_remove_index (info->states, info->states->len - 1);
17742
17743   if (info->states->len > 0)
17744     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17745   else
17746     {
17747       g_array_unref (info->states);
17748       info->states = NULL;
17749       info->cur_state = NULL;
17750     }
17751 }
17752
17753 /**
17754  * clutter_actor_set_content:
17755  * @self: a #ClutterActor
17756  * @content: (allow-none): a #ClutterContent, or %NULL
17757  *
17758  * Sets the contents of a #ClutterActor.
17759  *
17760  * Since: 1.10
17761  */
17762 void
17763 clutter_actor_set_content (ClutterActor   *self,
17764                            ClutterContent *content)
17765 {
17766   ClutterActorPrivate *priv;
17767
17768   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17769   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17770
17771   priv = self->priv;
17772
17773   if (priv->content != NULL)
17774     {
17775       _clutter_content_detached (priv->content, self);
17776       g_clear_object (&priv->content);
17777     }
17778
17779   priv->content = content;
17780
17781   if (priv->content != NULL)
17782     {
17783       g_object_ref (priv->content);
17784       _clutter_content_attached (priv->content, self);
17785     }
17786
17787   /* given that the content is always painted within the allocation,
17788    * we only need to queue a redraw here
17789    */
17790   clutter_actor_queue_redraw (self);
17791
17792   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17793
17794   /* if the content gravity is not resize-fill, and the new content has a
17795    * different preferred size than the previous one, then the content box
17796    * may have been changed. since we compute that lazily, we just notify
17797    * here, and let whomever watches :content-box do whatever they need to
17798    * do.
17799    */
17800   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17801     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17802 }
17803
17804 /**
17805  * clutter_actor_get_content:
17806  * @self: a #ClutterActor
17807  *
17808  * Retrieves the contents of @self.
17809  *
17810  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17811  *   or %NULL if none was set
17812  *
17813  * Since: 1.10
17814  */
17815 ClutterContent *
17816 clutter_actor_get_content (ClutterActor *self)
17817 {
17818   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17819
17820   return self->priv->content;
17821 }
17822
17823 /**
17824  * clutter_actor_set_content_gravity:
17825  * @self: a #ClutterActor
17826  * @gravity: the #ClutterContentGravity
17827  *
17828  * Sets the gravity of the #ClutterContent used by @self.
17829  *
17830  * See the description of the #ClutterActor:content-gravity property for
17831  * more information.
17832  *
17833  * The #ClutterActor:content-gravity property is animatable.
17834  *
17835  * Since: 1.10
17836  */
17837 void
17838 clutter_actor_set_content_gravity (ClutterActor *self,
17839                                    ClutterContentGravity  gravity)
17840 {
17841   ClutterActorPrivate *priv;
17842
17843   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17844
17845   priv = self->priv;
17846
17847   if (priv->content_gravity == gravity)
17848     return;
17849
17850   priv->content_box_valid = FALSE;
17851
17852   if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17853     {
17854       ClutterActorBox from_box, to_box;
17855
17856       clutter_actor_get_content_box (self, &from_box);
17857
17858       priv->content_gravity = gravity;
17859
17860       clutter_actor_get_content_box (self, &to_box);
17861
17862       _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17863                                         &from_box,
17864                                         &to_box);
17865     }
17866   else
17867     {
17868       ClutterActorBox to_box;
17869
17870       priv->content_gravity = gravity;
17871
17872       clutter_actor_get_content_box (self, &to_box);
17873
17874       _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17875                                         &to_box);
17876     }
17877
17878   clutter_actor_queue_redraw (self);
17879
17880   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17881 }
17882
17883 /**
17884  * clutter_actor_get_content_gravity:
17885  * @self: a #ClutterActor
17886  *
17887  * Retrieves the content gravity as set using
17888  * clutter_actor_get_content_gravity().
17889  *
17890  * Return value: the content gravity
17891  *
17892  * Since: 1.10
17893  */
17894 ClutterContentGravity
17895 clutter_actor_get_content_gravity (ClutterActor *self)
17896 {
17897   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17898                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17899
17900   return self->priv->content_gravity;
17901 }
17902
17903 /**
17904  * clutter_actor_get_content_box:
17905  * @self: a #ClutterActor
17906  * @box: (out caller-allocates): the return location for the bounding
17907  *   box for the #ClutterContent
17908  *
17909  * Retrieves the bounding box for the #ClutterContent of @self.
17910  *
17911  * The bounding box is relative to the actor's allocation.
17912  *
17913  * If no #ClutterContent is set for @self, or if @self has not been
17914  * allocated yet, then the result is undefined.
17915  *
17916  * The content box is guaranteed to be, at most, as big as the allocation
17917  * of the #ClutterActor.
17918  *
17919  * If the #ClutterContent used by the actor has a preferred size, then
17920  * it is possible to modify the content box by using the
17921  * #ClutterActor:content-gravity property.
17922  *
17923  * Since: 1.10
17924  */
17925 void
17926 clutter_actor_get_content_box (ClutterActor    *self,
17927                                ClutterActorBox *box)
17928 {
17929   ClutterActorPrivate *priv;
17930   gfloat content_w, content_h;
17931   gfloat alloc_w, alloc_h;
17932
17933   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17934   g_return_if_fail (box != NULL);
17935
17936   priv = self->priv;
17937
17938   box->x1 = 0.f;
17939   box->y1 = 0.f;
17940   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17941   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17942
17943   if (priv->content_box_valid)
17944     {
17945       *box = priv->content_box;
17946       return;
17947     }
17948
17949   /* no need to do any more work */
17950   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17951     return;
17952
17953   if (priv->content == NULL)
17954     return;
17955
17956   /* if the content does not have a preferred size then there is
17957    * no point in computing the content box
17958    */
17959   if (!clutter_content_get_preferred_size (priv->content,
17960                                            &content_w,
17961                                            &content_h))
17962     return;
17963
17964   alloc_w = box->x2;
17965   alloc_h = box->y2;
17966
17967   switch (priv->content_gravity)
17968     {
17969     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17970       box->x2 = box->x1 + MIN (content_w, alloc_w);
17971       box->y2 = box->y1 + MIN (content_h, alloc_h);
17972       break;
17973
17974     case CLUTTER_CONTENT_GRAVITY_TOP:
17975       if (alloc_w > content_w)
17976         {
17977           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17978           box->x2 = box->x1 + content_w;
17979         }
17980       box->y2 = box->y1 + MIN (content_h, alloc_h);
17981       break;
17982
17983     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17984       if (alloc_w > content_w)
17985         {
17986           box->x1 += (alloc_w - content_w);
17987           box->x2 = box->x1 + content_w;
17988         }
17989       box->y2 = box->y1 + MIN (content_h, alloc_h);
17990       break;
17991
17992     case CLUTTER_CONTENT_GRAVITY_LEFT:
17993       box->x2 = box->x1 + MIN (content_w, alloc_w);
17994       if (alloc_h > content_h)
17995         {
17996           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17997           box->y2 = box->y1 + content_h;
17998         }
17999       break;
18000
18001     case CLUTTER_CONTENT_GRAVITY_CENTER:
18002       if (alloc_w > content_w)
18003         {
18004           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18005           box->x2 = box->x1 + content_w;
18006         }
18007       if (alloc_h > content_h)
18008         {
18009           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18010           box->y2 = box->y1 + content_h;
18011         }
18012       break;
18013
18014     case CLUTTER_CONTENT_GRAVITY_RIGHT:
18015       if (alloc_w > content_w)
18016         {
18017           box->x1 += (alloc_w - content_w);
18018           box->x2 = box->x1 + content_w;
18019         }
18020       if (alloc_h > content_h)
18021         {
18022           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18023           box->y2 = box->y1 + content_h;
18024         }
18025       break;
18026
18027     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18028       box->x2 = box->x1 + MIN (content_w, alloc_w);
18029       if (alloc_h > content_h)
18030         {
18031           box->y1 += (alloc_h - content_h);
18032           box->y2 = box->y1 + content_h;
18033         }
18034       break;
18035
18036     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18037       if (alloc_w > content_w)
18038         {
18039           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18040           box->x2 = box->x1 + content_w;
18041         }
18042       if (alloc_h > content_h)
18043         {
18044           box->y1 += (alloc_h - content_h);
18045           box->y2 = box->y1 + content_h;
18046         }
18047       break;
18048
18049     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18050       if (alloc_w > content_w)
18051         {
18052           box->x1 += (alloc_w - content_w);
18053           box->x2 = box->x1 + content_w;
18054         }
18055       if (alloc_h > content_h)
18056         {
18057           box->y1 += (alloc_h - content_h);
18058           box->y2 = box->y1 + content_h;
18059         }
18060       break;
18061
18062     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18063       g_assert_not_reached ();
18064       break;
18065
18066     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18067       {
18068         double r_c = content_w / content_h;
18069         double r_a = alloc_w / alloc_h;
18070
18071         if (r_c >= 1.0)
18072           {
18073             if (r_a >= 1.0)
18074               {
18075                 box->x1 = 0.f;
18076                 box->x2 = alloc_w;
18077
18078                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18079                 box->y2 = box->y1 + (alloc_w * r_c);
18080               }
18081             else
18082               {
18083                 box->y1 = 0.f;
18084                 box->y2 = alloc_h;
18085
18086                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18087                 box->x2 = box->x1 + (alloc_h * r_c);
18088               }
18089           }
18090         else
18091           {
18092             if (r_a >= 1.0)
18093               {
18094                 box->y1 = 0.f;
18095                 box->y2 = alloc_h;
18096
18097                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18098                 box->x2 = box->x1 + (alloc_h * r_c);
18099               }
18100             else
18101               {
18102                 box->x1 = 0.f;
18103                 box->x2 = alloc_w;
18104
18105                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18106                 box->y2 = box->y1 + (alloc_w * r_c);
18107               }
18108           }
18109       }
18110       break;
18111     }
18112 }
18113
18114 /**
18115  * clutter_actor_set_content_scaling_filters:
18116  * @self: a #ClutterActor
18117  * @min_filter: the minification filter for the content
18118  * @mag_filter: the magnification filter for the content
18119  *
18120  * Sets the minification and magnification filter to be applied when
18121  * scaling the #ClutterActor:content of a #ClutterActor.
18122  *
18123  * The #ClutterActor:minification-filter will be used when reducing
18124  * the size of the content; the #ClutterActor:magnification-filter
18125  * will be used when increasing the size of the content.
18126  *
18127  * Since: 1.10
18128  */
18129 void
18130 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18131                                            ClutterScalingFilter  min_filter,
18132                                            ClutterScalingFilter  mag_filter)
18133 {
18134   ClutterActorPrivate *priv;
18135   gboolean changed;
18136   GObject *obj;
18137
18138   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18139
18140   priv = self->priv;
18141   obj = G_OBJECT (self);
18142
18143   g_object_freeze_notify (obj);
18144
18145   changed = FALSE;
18146
18147   if (priv->min_filter != min_filter)
18148     {
18149       priv->min_filter = min_filter;
18150       changed = TRUE;
18151
18152       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18153     }
18154
18155   if (priv->mag_filter != mag_filter)
18156     {
18157       priv->mag_filter = mag_filter;
18158       changed = TRUE;
18159
18160       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18161     }
18162
18163   if (changed)
18164     clutter_actor_queue_redraw (self);
18165
18166   g_object_thaw_notify (obj);
18167 }
18168
18169 /**
18170  * clutter_actor_get_content_scaling_filters:
18171  * @self: a #ClutterActor
18172  * @min_filter: (out) (allow-none): return location for the minification
18173  *   filter, or %NULL
18174  * @mag_filter: (out) (allow-none): return location for the magnification
18175  *   filter, or %NULL
18176  *
18177  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18178  *
18179  * Since: 1.10
18180  */
18181 void
18182 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18183                                            ClutterScalingFilter *min_filter,
18184                                            ClutterScalingFilter *mag_filter)
18185 {
18186   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18187
18188   if (min_filter != NULL)
18189     *min_filter = self->priv->min_filter;
18190
18191   if (mag_filter != NULL)
18192     *mag_filter = self->priv->mag_filter;
18193 }