actor: Add position and size animatable properties
[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   PROP_POSITION,
792   PROP_SIZE,
793
794   /* Then the rest of these size-related properties are the "actual"
795    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
796    */
797   PROP_FIXED_X,
798   PROP_FIXED_Y,
799
800   PROP_FIXED_POSITION_SET,
801
802   PROP_MIN_WIDTH,
803   PROP_MIN_WIDTH_SET,
804
805   PROP_MIN_HEIGHT,
806   PROP_MIN_HEIGHT_SET,
807
808   PROP_NATURAL_WIDTH,
809   PROP_NATURAL_WIDTH_SET,
810
811   PROP_NATURAL_HEIGHT,
812   PROP_NATURAL_HEIGHT_SET,
813
814   PROP_REQUEST_MODE,
815
816   /* Allocation properties are read-only */
817   PROP_ALLOCATION,
818
819   PROP_DEPTH,
820
821   PROP_CLIP,
822   PROP_HAS_CLIP,
823   PROP_CLIP_TO_ALLOCATION,
824
825   PROP_OPACITY,
826
827   PROP_OFFSCREEN_REDIRECT,
828
829   PROP_VISIBLE,
830   PROP_MAPPED,
831   PROP_REALIZED,
832   PROP_REACTIVE,
833
834   PROP_SCALE_X,
835   PROP_SCALE_Y,
836   PROP_SCALE_CENTER_X,
837   PROP_SCALE_CENTER_Y,
838   PROP_SCALE_GRAVITY,
839
840   PROP_ROTATION_ANGLE_X,
841   PROP_ROTATION_ANGLE_Y,
842   PROP_ROTATION_ANGLE_Z,
843   PROP_ROTATION_CENTER_X,
844   PROP_ROTATION_CENTER_Y,
845   PROP_ROTATION_CENTER_Z,
846   /* This property only makes sense for the z rotation because the
847      others would depend on the actor having a size along the
848      z-axis */
849   PROP_ROTATION_CENTER_Z_GRAVITY,
850
851   PROP_ANCHOR_X,
852   PROP_ANCHOR_Y,
853   PROP_ANCHOR_GRAVITY,
854
855   PROP_SHOW_ON_SET_PARENT,
856
857   PROP_TEXT_DIRECTION,
858   PROP_HAS_POINTER,
859
860   PROP_ACTIONS,
861   PROP_CONSTRAINTS,
862   PROP_EFFECT,
863
864   PROP_LAYOUT_MANAGER,
865
866   PROP_X_ALIGN,
867   PROP_Y_ALIGN,
868   PROP_MARGIN_TOP,
869   PROP_MARGIN_BOTTOM,
870   PROP_MARGIN_LEFT,
871   PROP_MARGIN_RIGHT,
872
873   PROP_BACKGROUND_COLOR,
874   PROP_BACKGROUND_COLOR_SET,
875
876   PROP_FIRST_CHILD,
877   PROP_LAST_CHILD,
878
879   PROP_CONTENT,
880   PROP_CONTENT_GRAVITY,
881   PROP_CONTENT_BOX,
882   PROP_MINIFICATION_FILTER,
883   PROP_MAGNIFICATION_FILTER,
884
885   PROP_LAST
886 };
887
888 static GParamSpec *obj_props[PROP_LAST];
889
890 enum
891 {
892   SHOW,
893   HIDE,
894   DESTROY,
895   PARENT_SET,
896   KEY_FOCUS_IN,
897   KEY_FOCUS_OUT,
898   PAINT,
899   PICK,
900   REALIZE,
901   UNREALIZE,
902   QUEUE_REDRAW,
903   QUEUE_RELAYOUT,
904   EVENT,
905   CAPTURED_EVENT,
906   BUTTON_PRESS_EVENT,
907   BUTTON_RELEASE_EVENT,
908   SCROLL_EVENT,
909   KEY_PRESS_EVENT,
910   KEY_RELEASE_EVENT,
911   MOTION_EVENT,
912   ENTER_EVENT,
913   LEAVE_EVENT,
914   ALLOCATION_CHANGED,
915   TRANSITIONS_COMPLETED,
916
917   LAST_SIGNAL
918 };
919
920 static guint actor_signals[LAST_SIGNAL] = { 0, };
921
922 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
923 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
924 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
925 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
926
927 /* These setters are all static for now, maybe they should be in the
928  * public API, but they are perhaps obscure enough to leave only as
929  * properties
930  */
931 static void clutter_actor_set_min_width          (ClutterActor *self,
932                                                   gfloat        min_width);
933 static void clutter_actor_set_min_height         (ClutterActor *self,
934                                                   gfloat        min_height);
935 static void clutter_actor_set_natural_width      (ClutterActor *self,
936                                                   gfloat        natural_width);
937 static void clutter_actor_set_natural_height     (ClutterActor *self,
938                                                   gfloat        natural_height);
939 static void clutter_actor_set_min_width_set      (ClutterActor *self,
940                                                   gboolean      use_min_width);
941 static void clutter_actor_set_min_height_set     (ClutterActor *self,
942                                                   gboolean      use_min_height);
943 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
944                                                   gboolean  use_natural_width);
945 static void clutter_actor_set_natural_height_set (ClutterActor *self,
946                                                   gboolean  use_natural_height);
947 static void clutter_actor_update_map_state       (ClutterActor  *self,
948                                                   MapStateChange change);
949 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
950
951 /* Helper routines for managing anchor coords */
952 static void clutter_anchor_coord_get_units (ClutterActor      *self,
953                                             const AnchorCoord *coord,
954                                             gfloat            *x,
955                                             gfloat            *y,
956                                             gfloat            *z);
957 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
958                                             gfloat             x,
959                                             gfloat             y,
960                                             gfloat             z);
961
962 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
963 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
964                                                         ClutterGravity     gravity);
965
966 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
967
968 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
969
970 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
971                                                                ClutterActor *ancestor,
972                                                                CoglMatrix *matrix);
973
974 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
975
976 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
977
978 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
979                                                                 const ClutterColor *color);
980
981 static void on_layout_manager_changed (ClutterLayoutManager *manager,
982                                        ClutterActor         *self);
983
984 /* Helper macro which translates by the anchor coord, applies the
985    given transformation and then translates back */
986 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
987   gfloat _tx, _ty, _tz;                                                \
988   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
989   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
990   { _transform; }                                                      \
991   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
992
993 static GQuark quark_shader_data = 0;
994 static GQuark quark_actor_layout_info = 0;
995 static GQuark quark_actor_transform_info = 0;
996 static GQuark quark_actor_animation_info = 0;
997
998 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
999                          clutter_actor,
1000                          G_TYPE_INITIALLY_UNOWNED,
1001                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
1002                                                 clutter_container_iface_init)
1003                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1004                                                 clutter_scriptable_iface_init)
1005                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1006                                                 clutter_animatable_iface_init)
1007                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1008                                                 atk_implementor_iface_init));
1009
1010 /*< private >
1011  * clutter_actor_get_debug_name:
1012  * @actor: a #ClutterActor
1013  *
1014  * Retrieves a printable name of @actor for debugging messages
1015  *
1016  * Return value: a string with a printable name
1017  */
1018 const gchar *
1019 _clutter_actor_get_debug_name (ClutterActor *actor)
1020 {
1021   return actor->priv->name != NULL ? actor->priv->name
1022                                    : G_OBJECT_TYPE_NAME (actor);
1023 }
1024
1025 #ifdef CLUTTER_ENABLE_DEBUG
1026 /* XXX - this is for debugging only, remove once working (or leave
1027  * in only in some debug mode). Should leave it for a little while
1028  * until we're confident in the new map/realize/visible handling.
1029  */
1030 static inline void
1031 clutter_actor_verify_map_state (ClutterActor *self)
1032 {
1033   ClutterActorPrivate *priv = self->priv;
1034
1035   if (CLUTTER_ACTOR_IS_REALIZED (self))
1036     {
1037       /* all bets are off during reparent when we're potentially realized,
1038        * but should not be according to invariants
1039        */
1040       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1041         {
1042           if (priv->parent == NULL)
1043             {
1044               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1045                 {
1046                 }
1047               else
1048                 g_warning ("Realized non-toplevel actor '%s' should "
1049                            "have a parent",
1050                            _clutter_actor_get_debug_name (self));
1051             }
1052           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1053             {
1054               g_warning ("Realized actor %s has an unrealized parent %s",
1055                          _clutter_actor_get_debug_name (self),
1056                          _clutter_actor_get_debug_name (priv->parent));
1057             }
1058         }
1059     }
1060
1061   if (CLUTTER_ACTOR_IS_MAPPED (self))
1062     {
1063       if (!CLUTTER_ACTOR_IS_REALIZED (self))
1064         g_warning ("Actor '%s' is mapped but not realized",
1065                    _clutter_actor_get_debug_name (self));
1066
1067       /* remaining bets are off during reparent when we're potentially
1068        * mapped, but should not be according to invariants
1069        */
1070       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1071         {
1072           if (priv->parent == NULL)
1073             {
1074               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1075                 {
1076                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1077                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1078                     {
1079                       g_warning ("Toplevel actor '%s' is mapped "
1080                                  "but not visible",
1081                                  _clutter_actor_get_debug_name (self));
1082                     }
1083                 }
1084               else
1085                 {
1086                   g_warning ("Mapped actor '%s' should have a parent",
1087                              _clutter_actor_get_debug_name (self));
1088                 }
1089             }
1090           else
1091             {
1092               ClutterActor *iter = self;
1093
1094               /* check for the enable_paint_unmapped flag on the actor
1095                * and parents; if the flag is enabled at any point of this
1096                * branch of the scene graph then all the later checks
1097                * become pointless
1098                */
1099               while (iter != NULL)
1100                 {
1101                   if (iter->priv->enable_paint_unmapped)
1102                     return;
1103
1104                   iter = iter->priv->parent;
1105                 }
1106
1107               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1108                 {
1109                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1110                              "is not visible",
1111                              _clutter_actor_get_debug_name (self),
1112                              _clutter_actor_get_debug_name (priv->parent));
1113                 }
1114
1115               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1116                 {
1117                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1118                              "is not realized",
1119                              _clutter_actor_get_debug_name (self),
1120                              _clutter_actor_get_debug_name (priv->parent));
1121                 }
1122
1123               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1124                 {
1125                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1126                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1127                                "parent '%s' is not mapped",
1128                                _clutter_actor_get_debug_name (self),
1129                                _clutter_actor_get_debug_name (priv->parent));
1130                 }
1131             }
1132         }
1133     }
1134 }
1135
1136 #endif /* CLUTTER_ENABLE_DEBUG */
1137
1138 static void
1139 clutter_actor_set_mapped (ClutterActor *self,
1140                           gboolean      mapped)
1141 {
1142   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1143     return;
1144
1145   if (mapped)
1146     {
1147       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1148       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1149     }
1150   else
1151     {
1152       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1153       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1154     }
1155 }
1156
1157 /* this function updates the mapped and realized states according to
1158  * invariants, in the appropriate order.
1159  */
1160 static void
1161 clutter_actor_update_map_state (ClutterActor  *self,
1162                                 MapStateChange change)
1163 {
1164   gboolean was_mapped;
1165
1166   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1167
1168   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1169     {
1170       /* the mapped flag on top-level actors must be set by the
1171        * per-backend implementation because it might be asynchronous.
1172        *
1173        * That is, the MAPPED flag on toplevels currently tracks the X
1174        * server mapped-ness of the window, while the expected behavior
1175        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1176        * This creates some weird complexity by breaking the invariant
1177        * that if we're visible and all ancestors shown then we are
1178        * also mapped - instead, we are mapped if all ancestors
1179        * _possibly excepting_ the stage are mapped. The stage
1180        * will map/unmap for example when it is minimized or
1181        * moved to another workspace.
1182        *
1183        * So, the only invariant on the stage is that if visible it
1184        * should be realized, and that it has to be visible to be
1185        * mapped.
1186        */
1187       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1188         clutter_actor_realize (self);
1189
1190       switch (change)
1191         {
1192         case MAP_STATE_CHECK:
1193           break;
1194
1195         case MAP_STATE_MAKE_MAPPED:
1196           g_assert (!was_mapped);
1197           clutter_actor_set_mapped (self, TRUE);
1198           break;
1199
1200         case MAP_STATE_MAKE_UNMAPPED:
1201           g_assert (was_mapped);
1202           clutter_actor_set_mapped (self, FALSE);
1203           break;
1204
1205         case MAP_STATE_MAKE_UNREALIZED:
1206           /* we only use MAKE_UNREALIZED in unparent,
1207            * and unparenting a stage isn't possible.
1208            * If someone wants to just unrealize a stage
1209            * then clutter_actor_unrealize() doesn't
1210            * go through this codepath.
1211            */
1212           g_warning ("Trying to force unrealize stage is not allowed");
1213           break;
1214         }
1215
1216       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1217           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1218           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1219         {
1220           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1221                      "it is somehow still mapped",
1222                      _clutter_actor_get_debug_name (self));
1223         }
1224     }
1225   else
1226     {
1227       ClutterActorPrivate *priv = self->priv;
1228       ClutterActor *parent = priv->parent;
1229       gboolean should_be_mapped;
1230       gboolean may_be_realized;
1231       gboolean must_be_realized;
1232
1233       should_be_mapped = FALSE;
1234       may_be_realized = TRUE;
1235       must_be_realized = FALSE;
1236
1237       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1238         {
1239           may_be_realized = FALSE;
1240         }
1241       else
1242         {
1243           /* Maintain invariant that if parent is mapped, and we are
1244            * visible, then we are mapped ...  unless parent is a
1245            * stage, in which case we map regardless of parent's map
1246            * state but do require stage to be visible and realized.
1247            *
1248            * If parent is realized, that does not force us to be
1249            * realized; but if parent is unrealized, that does force
1250            * us to be unrealized.
1251            *
1252            * The reason we don't force children to realize with
1253            * parents is _clutter_actor_rerealize(); if we require that
1254            * a realized parent means children are realized, then to
1255            * unrealize an actor we would have to unrealize its
1256            * parents, which would end up meaning unrealizing and
1257            * hiding the entire stage. So we allow unrealizing a
1258            * child (as long as that child is not mapped) while that
1259            * child still has a realized parent.
1260            *
1261            * Also, if we unrealize from leaf nodes to root, and
1262            * realize from root to leaf, the invariants are never
1263            * violated if we allow children to be unrealized
1264            * while parents are realized.
1265            *
1266            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1267            * to force us to unmap, even though parent is still
1268            * mapped. This is because we're unmapping from leaf nodes
1269            * up to root nodes.
1270            */
1271           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1272               change != MAP_STATE_MAKE_UNMAPPED)
1273             {
1274               gboolean parent_is_visible_realized_toplevel;
1275
1276               parent_is_visible_realized_toplevel =
1277                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1278                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1279                  CLUTTER_ACTOR_IS_REALIZED (parent));
1280
1281               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1282                   parent_is_visible_realized_toplevel)
1283                 {
1284                   must_be_realized = TRUE;
1285                   should_be_mapped = TRUE;
1286                 }
1287             }
1288
1289           /* if the actor has been set to be painted even if unmapped
1290            * then we should map it and check for realization as well;
1291            * this is an override for the branch of the scene graph
1292            * which begins with this node
1293            */
1294           if (priv->enable_paint_unmapped)
1295             {
1296               if (priv->parent == NULL)
1297                 g_warning ("Attempting to map an unparented actor '%s'",
1298                            _clutter_actor_get_debug_name (self));
1299
1300               should_be_mapped = TRUE;
1301               must_be_realized = TRUE;
1302             }
1303
1304           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1305             may_be_realized = FALSE;
1306         }
1307
1308       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1309         {
1310           if (parent == NULL)
1311             g_warning ("Attempting to map a child that does not "
1312                        "meet the necessary invariants: the actor '%s' "
1313                        "has no parent",
1314                        _clutter_actor_get_debug_name (self));
1315           else
1316             g_warning ("Attempting to map a child that does not "
1317                        "meet the necessary invariants: the actor '%s' "
1318                        "is parented to an unmapped actor '%s'",
1319                        _clutter_actor_get_debug_name (self),
1320                        _clutter_actor_get_debug_name (priv->parent));
1321         }
1322
1323       /* If in reparent, we temporarily suspend unmap and unrealize.
1324        *
1325        * We want to go in the order "realize, map" and "unmap, unrealize"
1326        */
1327
1328       /* Unmap */
1329       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1330         clutter_actor_set_mapped (self, FALSE);
1331
1332       /* Realize */
1333       if (must_be_realized)
1334         clutter_actor_realize (self);
1335
1336       /* if we must be realized then we may be, presumably */
1337       g_assert (!(must_be_realized && !may_be_realized));
1338
1339       /* Unrealize */
1340       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1341         clutter_actor_unrealize_not_hiding (self);
1342
1343       /* Map */
1344       if (should_be_mapped)
1345         {
1346           if (!must_be_realized)
1347             g_warning ("Somehow we think actor '%s' should be mapped but "
1348                        "not realized, which isn't allowed",
1349                        _clutter_actor_get_debug_name (self));
1350
1351           /* realization is allowed to fail (though I don't know what
1352            * an app is supposed to do about that - shouldn't it just
1353            * be a g_error? anyway, we have to avoid mapping if this
1354            * happens)
1355            */
1356           if (CLUTTER_ACTOR_IS_REALIZED (self))
1357             clutter_actor_set_mapped (self, TRUE);
1358         }
1359     }
1360
1361 #ifdef CLUTTER_ENABLE_DEBUG
1362   /* check all invariants were kept */
1363   clutter_actor_verify_map_state (self);
1364 #endif
1365 }
1366
1367 static void
1368 clutter_actor_real_map (ClutterActor *self)
1369 {
1370   ClutterActorPrivate *priv = self->priv;
1371   ClutterActor *stage, *iter;
1372
1373   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1374
1375   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1376                 _clutter_actor_get_debug_name (self));
1377
1378   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1379
1380   stage = _clutter_actor_get_stage_internal (self);
1381   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1382
1383   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1384                 priv->pick_id,
1385                 _clutter_actor_get_debug_name (self));
1386
1387   /* notify on parent mapped before potentially mapping
1388    * children, so apps see a top-down notification.
1389    */
1390   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1391
1392   for (iter = self->priv->first_child;
1393        iter != NULL;
1394        iter = iter->priv->next_sibling)
1395     {
1396       clutter_actor_map (iter);
1397     }
1398 }
1399
1400 /**
1401  * clutter_actor_map:
1402  * @self: A #ClutterActor
1403  *
1404  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1405  * and realizes its children if they are visible. Does nothing if the
1406  * actor is not visible.
1407  *
1408  * Calling this function is strongly disencouraged: the default
1409  * implementation of #ClutterActorClass.map() will map all the children
1410  * of an actor when mapping its parent.
1411  *
1412  * When overriding map, it is mandatory to chain up to the parent
1413  * implementation.
1414  *
1415  * Since: 1.0
1416  */
1417 void
1418 clutter_actor_map (ClutterActor *self)
1419 {
1420   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1421
1422   if (CLUTTER_ACTOR_IS_MAPPED (self))
1423     return;
1424
1425   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1426     return;
1427
1428   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1429 }
1430
1431 static void
1432 clutter_actor_real_unmap (ClutterActor *self)
1433 {
1434   ClutterActorPrivate *priv = self->priv;
1435   ClutterActor *iter;
1436
1437   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1438
1439   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1440                 _clutter_actor_get_debug_name (self));
1441
1442   for (iter = self->priv->first_child;
1443        iter != NULL;
1444        iter = iter->priv->next_sibling)
1445     {
1446       clutter_actor_unmap (iter);
1447     }
1448
1449   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1450
1451   /* clear the contents of the last paint volume, so that hiding + moving +
1452    * showing will not result in the wrong area being repainted
1453    */
1454   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1455   priv->last_paint_volume_valid = TRUE;
1456
1457   /* notify on parent mapped after potentially unmapping
1458    * children, so apps see a bottom-up notification.
1459    */
1460   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1461
1462   /* relinquish keyboard focus if we were unmapped while owning it */
1463   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1464     {
1465       ClutterStage *stage;
1466
1467       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1468
1469       if (stage != NULL)
1470         _clutter_stage_release_pick_id (stage, priv->pick_id);
1471
1472       priv->pick_id = -1;
1473
1474       if (stage != NULL &&
1475           clutter_stage_get_key_focus (stage) == self)
1476         {
1477           clutter_stage_set_key_focus (stage, NULL);
1478         }
1479     }
1480 }
1481
1482 /**
1483  * clutter_actor_unmap:
1484  * @self: A #ClutterActor
1485  *
1486  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1487  * unmaps its children if they were mapped.
1488  *
1489  * Calling this function is not encouraged: the default #ClutterActor
1490  * implementation of #ClutterActorClass.unmap() will also unmap any
1491  * eventual children by default when their parent is unmapped.
1492  *
1493  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1494  * chain up to the parent implementation.
1495  *
1496  * <note>It is important to note that the implementation of the
1497  * #ClutterActorClass.unmap() virtual function may be called after
1498  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1499  * implementation, but it is guaranteed to be called before the
1500  * #GObjectClass.finalize() implementation.</note>
1501  *
1502  * Since: 1.0
1503  */
1504 void
1505 clutter_actor_unmap (ClutterActor *self)
1506 {
1507   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1508
1509   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1510     return;
1511
1512   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1513 }
1514
1515 static void
1516 clutter_actor_real_show (ClutterActor *self)
1517 {
1518   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1519     {
1520       ClutterActorPrivate *priv = self->priv;
1521
1522       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1523
1524       /* we notify on the "visible" flag in the clutter_actor_show()
1525        * wrapper so the entire show signal emission completes first
1526        * (?)
1527        */
1528       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1529
1530       /* we queue a relayout unless the actor is inside a
1531        * container that explicitly told us not to
1532        */
1533       if (priv->parent != NULL &&
1534           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1535         {
1536           /* While an actor is hidden the parent may not have
1537            * allocated/requested so we need to start from scratch
1538            * and avoid the short-circuiting in
1539            * clutter_actor_queue_relayout().
1540            */
1541           priv->needs_width_request  = FALSE;
1542           priv->needs_height_request = FALSE;
1543           priv->needs_allocation     = FALSE;
1544           clutter_actor_queue_relayout (self);
1545         }
1546     }
1547 }
1548
1549 static inline void
1550 set_show_on_set_parent (ClutterActor *self,
1551                         gboolean      set_show)
1552 {
1553   ClutterActorPrivate *priv = self->priv;
1554
1555   set_show = !!set_show;
1556
1557   if (priv->show_on_set_parent == set_show)
1558     return;
1559
1560   if (priv->parent == NULL)
1561     {
1562       priv->show_on_set_parent = set_show;
1563       g_object_notify_by_pspec (G_OBJECT (self),
1564                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1565     }
1566 }
1567
1568 /**
1569  * clutter_actor_show:
1570  * @self: A #ClutterActor
1571  *
1572  * Flags an actor to be displayed. An actor that isn't shown will not
1573  * be rendered on the stage.
1574  *
1575  * Actors are visible by default.
1576  *
1577  * If this function is called on an actor without a parent, the
1578  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1579  * effect.
1580  */
1581 void
1582 clutter_actor_show (ClutterActor *self)
1583 {
1584   ClutterActorPrivate *priv;
1585
1586   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1587
1588   /* simple optimization */
1589   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1590     {
1591       /* we still need to set the :show-on-set-parent property, in
1592        * case show() is called on an unparented actor
1593        */
1594       set_show_on_set_parent (self, TRUE);
1595       return;
1596     }
1597
1598 #ifdef CLUTTER_ENABLE_DEBUG
1599   clutter_actor_verify_map_state (self);
1600 #endif
1601
1602   priv = self->priv;
1603
1604   g_object_freeze_notify (G_OBJECT (self));
1605
1606   set_show_on_set_parent (self, TRUE);
1607
1608   g_signal_emit (self, actor_signals[SHOW], 0);
1609   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1610
1611   if (priv->parent != NULL)
1612     clutter_actor_queue_redraw (priv->parent);
1613
1614   g_object_thaw_notify (G_OBJECT (self));
1615 }
1616
1617 /**
1618  * clutter_actor_show_all:
1619  * @self: a #ClutterActor
1620  *
1621  * Calls clutter_actor_show() on all children of an actor (if any).
1622  *
1623  * Since: 0.2
1624  *
1625  * Deprecated: 1.10: Actors are visible by default
1626  */
1627 void
1628 clutter_actor_show_all (ClutterActor *self)
1629 {
1630   ClutterActorClass *klass;
1631
1632   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1633
1634   klass = CLUTTER_ACTOR_GET_CLASS (self);
1635   if (klass->show_all)
1636     klass->show_all (self);
1637 }
1638
1639 static void
1640 clutter_actor_real_hide (ClutterActor *self)
1641 {
1642   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1643     {
1644       ClutterActorPrivate *priv = self->priv;
1645
1646       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1647
1648       /* we notify on the "visible" flag in the clutter_actor_hide()
1649        * wrapper so the entire hide signal emission completes first
1650        * (?)
1651        */
1652       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1653
1654       /* we queue a relayout unless the actor is inside a
1655        * container that explicitly told us not to
1656        */
1657       if (priv->parent != NULL &&
1658           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1659         clutter_actor_queue_relayout (priv->parent);
1660     }
1661 }
1662
1663 /**
1664  * clutter_actor_hide:
1665  * @self: A #ClutterActor
1666  *
1667  * Flags an actor to be hidden. A hidden actor will not be
1668  * rendered on the stage.
1669  *
1670  * Actors are visible by default.
1671  *
1672  * If this function is called on an actor without a parent, the
1673  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1674  * as a side-effect.
1675  */
1676 void
1677 clutter_actor_hide (ClutterActor *self)
1678 {
1679   ClutterActorPrivate *priv;
1680
1681   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1682
1683   /* simple optimization */
1684   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1685     {
1686       /* we still need to set the :show-on-set-parent property, in
1687        * case hide() is called on an unparented actor
1688        */
1689       set_show_on_set_parent (self, FALSE);
1690       return;
1691     }
1692
1693 #ifdef CLUTTER_ENABLE_DEBUG
1694   clutter_actor_verify_map_state (self);
1695 #endif
1696
1697   priv = self->priv;
1698
1699   g_object_freeze_notify (G_OBJECT (self));
1700
1701   set_show_on_set_parent (self, FALSE);
1702
1703   g_signal_emit (self, actor_signals[HIDE], 0);
1704   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1705
1706   if (priv->parent != NULL)
1707     clutter_actor_queue_redraw (priv->parent);
1708
1709   g_object_thaw_notify (G_OBJECT (self));
1710 }
1711
1712 /**
1713  * clutter_actor_hide_all:
1714  * @self: a #ClutterActor
1715  *
1716  * Calls clutter_actor_hide() on all child actors (if any).
1717  *
1718  * Since: 0.2
1719  *
1720  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1721  *   prevent its children from being painted as well.
1722  */
1723 void
1724 clutter_actor_hide_all (ClutterActor *self)
1725 {
1726   ClutterActorClass *klass;
1727
1728   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1729
1730   klass = CLUTTER_ACTOR_GET_CLASS (self);
1731   if (klass->hide_all)
1732     klass->hide_all (self);
1733 }
1734
1735 /**
1736  * clutter_actor_realize:
1737  * @self: A #ClutterActor
1738  *
1739  * Realization informs the actor that it is attached to a stage. It
1740  * can use this to allocate resources if it wanted to delay allocation
1741  * until it would be rendered. However it is perfectly acceptable for
1742  * an actor to create resources before being realized because Clutter
1743  * only ever has a single rendering context so that actor is free to
1744  * be moved from one stage to another.
1745  *
1746  * This function does nothing if the actor is already realized.
1747  *
1748  * Because a realized actor must have realized parent actors, calling
1749  * clutter_actor_realize() will also realize all parents of the actor.
1750  *
1751  * This function does not realize child actors, except in the special
1752  * case that realizing the stage, when the stage is visible, will
1753  * suddenly map (and thus realize) the children of the stage.
1754  **/
1755 void
1756 clutter_actor_realize (ClutterActor *self)
1757 {
1758   ClutterActorPrivate *priv;
1759
1760   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1761
1762   priv = self->priv;
1763
1764 #ifdef CLUTTER_ENABLE_DEBUG
1765   clutter_actor_verify_map_state (self);
1766 #endif
1767
1768   if (CLUTTER_ACTOR_IS_REALIZED (self))
1769     return;
1770
1771   /* To be realized, our parent actors must be realized first.
1772    * This will only succeed if we're inside a toplevel.
1773    */
1774   if (priv->parent != NULL)
1775     clutter_actor_realize (priv->parent);
1776
1777   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1778     {
1779       /* toplevels can be realized at any time */
1780     }
1781   else
1782     {
1783       /* "Fail" the realization if parent is missing or unrealized;
1784        * this should really be a g_warning() not some kind of runtime
1785        * failure; how can an app possibly recover? Instead it's a bug
1786        * in the app and the app should get an explanatory warning so
1787        * someone can fix it. But for now it's too hard to fix this
1788        * because e.g. ClutterTexture needs reworking.
1789        */
1790       if (priv->parent == NULL ||
1791           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1792         return;
1793     }
1794
1795   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1796
1797   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1798   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1799
1800   g_signal_emit (self, actor_signals[REALIZE], 0);
1801
1802   /* Stage actor is allowed to unset the realized flag again in its
1803    * default signal handler, though that is a pathological situation.
1804    */
1805
1806   /* If realization "failed" we'll have to update child state. */
1807   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1808 }
1809
1810 static void
1811 clutter_actor_real_unrealize (ClutterActor *self)
1812 {
1813   /* we must be unmapped (implying our children are also unmapped) */
1814   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1815 }
1816
1817 /**
1818  * clutter_actor_unrealize:
1819  * @self: A #ClutterActor
1820  *
1821  * Unrealization informs the actor that it may be being destroyed or
1822  * moved to another stage. The actor may want to destroy any
1823  * underlying graphics resources at this point. However it is
1824  * perfectly acceptable for it to retain the resources until the actor
1825  * is destroyed because Clutter only ever uses a single rendering
1826  * context and all of the graphics resources are valid on any stage.
1827  *
1828  * Because mapped actors must be realized, actors may not be
1829  * unrealized if they are mapped. This function hides the actor to be
1830  * sure it isn't mapped, an application-visible side effect that you
1831  * may not be expecting.
1832  *
1833  * This function should not be called by application code.
1834  */
1835 void
1836 clutter_actor_unrealize (ClutterActor *self)
1837 {
1838   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1839   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1840
1841 /* This function should not really be in the public API, because
1842  * there isn't a good reason to call it. ClutterActor will already
1843  * unrealize things for you when it's important to do so.
1844  *
1845  * If you were using clutter_actor_unrealize() in a dispose
1846  * implementation, then don't, just chain up to ClutterActor's
1847  * dispose.
1848  *
1849  * If you were using clutter_actor_unrealize() to implement
1850  * unrealizing children of your container, then don't, ClutterActor
1851  * will already take care of that.
1852  *
1853  * If you were using clutter_actor_unrealize() to re-realize to
1854  * create your resources in a different way, then use
1855  * _clutter_actor_rerealize() (inside Clutter) or just call your
1856  * code that recreates your resources directly (outside Clutter).
1857  */
1858
1859 #ifdef CLUTTER_ENABLE_DEBUG
1860   clutter_actor_verify_map_state (self);
1861 #endif
1862
1863   clutter_actor_hide (self);
1864
1865   clutter_actor_unrealize_not_hiding (self);
1866 }
1867
1868 static ClutterActorTraverseVisitFlags
1869 unrealize_actor_before_children_cb (ClutterActor *self,
1870                                     int depth,
1871                                     void *user_data)
1872 {
1873   /* If an actor is already unrealized we know its children have also
1874    * already been unrealized... */
1875   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1876     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1877
1878   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1879
1880   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1881 }
1882
1883 static ClutterActorTraverseVisitFlags
1884 unrealize_actor_after_children_cb (ClutterActor *self,
1885                                    int depth,
1886                                    void *user_data)
1887 {
1888   /* We want to unset the realized flag only _after_
1889    * child actors are unrealized, to maintain invariants.
1890    */
1891   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1892   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1893   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1894 }
1895
1896 /*
1897  * clutter_actor_unrealize_not_hiding:
1898  * @self: A #ClutterActor
1899  *
1900  * Unrealization informs the actor that it may be being destroyed or
1901  * moved to another stage. The actor may want to destroy any
1902  * underlying graphics resources at this point. However it is
1903  * perfectly acceptable for it to retain the resources until the actor
1904  * is destroyed because Clutter only ever uses a single rendering
1905  * context and all of the graphics resources are valid on any stage.
1906  *
1907  * Because mapped actors must be realized, actors may not be
1908  * unrealized if they are mapped. You must hide the actor or one of
1909  * its parents before attempting to unrealize.
1910  *
1911  * This function is separate from clutter_actor_unrealize() because it
1912  * does not automatically hide the actor.
1913  * Actors need not be hidden to be unrealized, they just need to
1914  * be unmapped. In fact we don't want to mess up the application's
1915  * setting of the "visible" flag, so hiding is very undesirable.
1916  *
1917  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1918  * backward compatibility.
1919  */
1920 static void
1921 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1922 {
1923   _clutter_actor_traverse (self,
1924                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1925                            unrealize_actor_before_children_cb,
1926                            unrealize_actor_after_children_cb,
1927                            NULL);
1928 }
1929
1930 /*
1931  * _clutter_actor_rerealize:
1932  * @self: A #ClutterActor
1933  * @callback: Function to call while unrealized
1934  * @data: data for callback
1935  *
1936  * If an actor is already unrealized, this just calls the callback.
1937  *
1938  * If it is realized, it unrealizes temporarily, calls the callback,
1939  * and then re-realizes the actor.
1940  *
1941  * As a side effect, leaves all children of the actor unrealized if
1942  * the actor was realized but not showing.  This is because when we
1943  * unrealize the actor temporarily we must unrealize its children
1944  * (e.g. children of a stage can't be realized if stage window is
1945  * gone). And we aren't clever enough to save the realization state of
1946  * all children. In most cases this should not matter, because
1947  * the children will automatically realize when they next become mapped.
1948  */
1949 void
1950 _clutter_actor_rerealize (ClutterActor    *self,
1951                           ClutterCallback  callback,
1952                           void            *data)
1953 {
1954   gboolean was_mapped;
1955   gboolean was_showing;
1956   gboolean was_realized;
1957
1958   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1959
1960 #ifdef CLUTTER_ENABLE_DEBUG
1961   clutter_actor_verify_map_state (self);
1962 #endif
1963
1964   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1965   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1966   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1967
1968   /* Must be unmapped to unrealize. Note we only have to hide this
1969    * actor if it was mapped (if all parents were showing).  If actor
1970    * is merely visible (but not mapped), then that's fine, we can
1971    * leave it visible.
1972    */
1973   if (was_mapped)
1974     clutter_actor_hide (self);
1975
1976   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1977
1978   /* unrealize self and all children */
1979   clutter_actor_unrealize_not_hiding (self);
1980
1981   if (callback != NULL)
1982     {
1983       (* callback) (self, data);
1984     }
1985
1986   if (was_showing)
1987     clutter_actor_show (self); /* will realize only if mapping implies it */
1988   else if (was_realized)
1989     clutter_actor_realize (self); /* realize self and all parents */
1990 }
1991
1992 static void
1993 clutter_actor_real_pick (ClutterActor       *self,
1994                          const ClutterColor *color)
1995 {
1996   /* the default implementation is just to paint a rectangle
1997    * with the same size of the actor using the passed color
1998    */
1999   if (clutter_actor_should_pick_paint (self))
2000     {
2001       ClutterActorBox box = { 0, };
2002       float width, height;
2003
2004       clutter_actor_get_allocation_box (self, &box);
2005
2006       width = box.x2 - box.x1;
2007       height = box.y2 - box.y1;
2008
2009       cogl_set_source_color4ub (color->red,
2010                                 color->green,
2011                                 color->blue,
2012                                 color->alpha);
2013
2014       cogl_rectangle (0, 0, width, height);
2015     }
2016
2017   /* XXX - this thoroughly sucks, but we need to maintain compatibility
2018    * with existing container classes that override the pick() virtual
2019    * and chain up to the default implementation - otherwise we'll end up
2020    * painting our children twice.
2021    *
2022    * this has to go away for 2.0; hopefully along the pick() itself.
2023    */
2024   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2025     {
2026       ClutterActor *iter;
2027
2028       for (iter = self->priv->first_child;
2029            iter != NULL;
2030            iter = iter->priv->next_sibling)
2031         clutter_actor_paint (iter);
2032     }
2033 }
2034
2035 /**
2036  * clutter_actor_should_pick_paint:
2037  * @self: A #ClutterActor
2038  *
2039  * Should be called inside the implementation of the
2040  * #ClutterActor::pick virtual function in order to check whether
2041  * the actor should paint itself in pick mode or not.
2042  *
2043  * This function should never be called directly by applications.
2044  *
2045  * Return value: %TRUE if the actor should paint its silhouette,
2046  *   %FALSE otherwise
2047  */
2048 gboolean
2049 clutter_actor_should_pick_paint (ClutterActor *self)
2050 {
2051   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2052
2053   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2054       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2055        CLUTTER_ACTOR_IS_REACTIVE (self)))
2056     return TRUE;
2057
2058   return FALSE;
2059 }
2060
2061 static void
2062 clutter_actor_real_get_preferred_width (ClutterActor *self,
2063                                         gfloat        for_height,
2064                                         gfloat       *min_width_p,
2065                                         gfloat       *natural_width_p)
2066 {
2067   ClutterActorPrivate *priv = self->priv;
2068
2069   if (priv->n_children != 0 &&
2070       priv->layout_manager != NULL)
2071     {
2072       ClutterContainer *container = CLUTTER_CONTAINER (self);
2073
2074       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2075                     "for the preferred width",
2076                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2077                     priv->layout_manager);
2078
2079       clutter_layout_manager_get_preferred_width (priv->layout_manager,
2080                                                   container,
2081                                                   for_height,
2082                                                   min_width_p,
2083                                                   natural_width_p);
2084
2085       return;
2086     }
2087
2088   /* Default implementation is always 0x0, usually an actor
2089    * using this default is relying on someone to set the
2090    * request manually
2091    */
2092   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2093
2094   if (min_width_p)
2095     *min_width_p = 0;
2096
2097   if (natural_width_p)
2098     *natural_width_p = 0;
2099 }
2100
2101 static void
2102 clutter_actor_real_get_preferred_height (ClutterActor *self,
2103                                          gfloat        for_width,
2104                                          gfloat       *min_height_p,
2105                                          gfloat       *natural_height_p)
2106 {
2107   ClutterActorPrivate *priv = self->priv;
2108
2109   if (priv->n_children != 0 &&
2110       priv->layout_manager != NULL)
2111     {
2112       ClutterContainer *container = CLUTTER_CONTAINER (self);
2113
2114       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2115                     "for the preferred height",
2116                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2117                     priv->layout_manager);
2118
2119       clutter_layout_manager_get_preferred_height (priv->layout_manager,
2120                                                    container,
2121                                                    for_width,
2122                                                    min_height_p,
2123                                                    natural_height_p);
2124
2125       return;
2126     }
2127   /* Default implementation is always 0x0, usually an actor
2128    * using this default is relying on someone to set the
2129    * request manually
2130    */
2131   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2132
2133   if (min_height_p)
2134     *min_height_p = 0;
2135
2136   if (natural_height_p)
2137     *natural_height_p = 0;
2138 }
2139
2140 static void
2141 clutter_actor_store_old_geometry (ClutterActor    *self,
2142                                   ClutterActorBox *box)
2143 {
2144   *box = self->priv->allocation;
2145 }
2146
2147 static inline void
2148 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2149                                           const ClutterActorBox *old)
2150 {
2151   ClutterActorPrivate *priv = self->priv;
2152   GObject *obj = G_OBJECT (self);
2153
2154   g_object_freeze_notify (obj);
2155
2156   /* to avoid excessive requisition or allocation cycles we
2157    * use the cached values.
2158    *
2159    * - if we don't have an allocation we assume that we need
2160    *   to notify anyway
2161    * - if we don't have a width or a height request we notify
2162    *   width and height
2163    * - if we have a valid allocation then we check the old
2164    *   bounding box with the current allocation and we notify
2165    *   the changes
2166    */
2167   if (priv->needs_allocation)
2168     {
2169       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2170       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2171       g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2172       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2173       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2174       g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2175     }
2176   else if (priv->needs_width_request || priv->needs_height_request)
2177     {
2178       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2179       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2180       g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2181     }
2182   else
2183     {
2184       gfloat x, y;
2185       gfloat width, height;
2186
2187       x = priv->allocation.x1;
2188       y = priv->allocation.y1;
2189       width = priv->allocation.x2 - priv->allocation.x1;
2190       height = priv->allocation.y2 - priv->allocation.y1;
2191
2192       if (x != old->x1)
2193         {
2194           g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2195           g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2196         }
2197
2198       if (y != old->y1)
2199         {
2200           g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2201           g_object_notify_by_pspec (obj, obj_props[PROP_POSITION]);
2202         }
2203
2204       if (width != (old->x2 - old->x1))
2205         {
2206           g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2207           g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2208         }
2209
2210       if (height != (old->y2 - old->y1))
2211         {
2212           g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2213           g_object_notify_by_pspec (obj, obj_props[PROP_SIZE]);
2214         }
2215     }
2216
2217   g_object_thaw_notify (obj);
2218 }
2219
2220 /*< private >
2221  * clutter_actor_set_allocation_internal:
2222  * @self: a #ClutterActor
2223  * @box: a #ClutterActorBox
2224  * @flags: allocation flags
2225  *
2226  * Stores the allocation of @self.
2227  *
2228  * This function only performs basic storage and property notification.
2229  *
2230  * This function should be called by clutter_actor_set_allocation()
2231  * and by the default implementation of #ClutterActorClass.allocate().
2232  *
2233  * Return value: %TRUE if the allocation of the #ClutterActor has been
2234  *   changed, and %FALSE otherwise
2235  */
2236 static inline gboolean
2237 clutter_actor_set_allocation_internal (ClutterActor           *self,
2238                                        const ClutterActorBox  *box,
2239                                        ClutterAllocationFlags  flags)
2240 {
2241   ClutterActorPrivate *priv = self->priv;
2242   GObject *obj;
2243   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2244   gboolean flags_changed;
2245   gboolean retval;
2246   ClutterActorBox old_alloc = { 0, };
2247
2248   obj = G_OBJECT (self);
2249
2250   g_object_freeze_notify (obj);
2251
2252   clutter_actor_store_old_geometry (self, &old_alloc);
2253
2254   x1_changed = priv->allocation.x1 != box->x1;
2255   y1_changed = priv->allocation.y1 != box->y1;
2256   x2_changed = priv->allocation.x2 != box->x2;
2257   y2_changed = priv->allocation.y2 != box->y2;
2258
2259   flags_changed = priv->allocation_flags != flags;
2260
2261   priv->allocation = *box;
2262   priv->allocation_flags = flags;
2263
2264   /* allocation is authoritative */
2265   priv->needs_width_request = FALSE;
2266   priv->needs_height_request = FALSE;
2267   priv->needs_allocation = FALSE;
2268
2269   if (x1_changed || y1_changed ||
2270       x2_changed || y2_changed ||
2271       flags_changed)
2272     {
2273       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2274                     _clutter_actor_get_debug_name (self));
2275
2276       priv->transform_valid = FALSE;
2277
2278       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2279
2280       /* if the allocation changes, so does the content box */
2281       if (priv->content != NULL)
2282         {
2283           priv->content_box_valid = FALSE;
2284           g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2285         }
2286
2287       retval = TRUE;
2288     }
2289   else
2290     retval = FALSE;
2291
2292   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2293
2294   g_object_thaw_notify (obj);
2295
2296   return retval;
2297 }
2298
2299 static void clutter_actor_real_allocate (ClutterActor           *self,
2300                                          const ClutterActorBox  *box,
2301                                          ClutterAllocationFlags  flags);
2302
2303 static inline void
2304 clutter_actor_maybe_layout_children (ClutterActor           *self,
2305                                      const ClutterActorBox  *allocation,
2306                                      ClutterAllocationFlags  flags)
2307 {
2308   ClutterActorPrivate *priv = self->priv;
2309
2310   /* this is going to be a bit hard to follow, so let's put an explanation
2311    * here.
2312    *
2313    * we want ClutterActor to have a default layout manager if the actor was
2314    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2315    *
2316    * we also want any subclass of ClutterActor that does not override the
2317    * ::allocate() virtual function to delegate to a layout manager.
2318    *
2319    * finally, we want to allow people subclassing ClutterActor and overriding
2320    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2321    *
2322    * on the other hand, we want existing actor subclasses overriding the
2323    * ::allocate() virtual function and chaining up to the parent's
2324    * implementation to continue working without allocating their children
2325    * twice, or without entering an allocation loop.
2326    *
2327    * for the first two points, we check if the class of the actor is
2328    * overridding the ::allocate() virtual function; if it isn't, then we
2329    * follow through with checking whether we have children and a layout
2330    * manager, and eventually calling clutter_layout_manager_allocate().
2331    *
2332    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2333    * allocation flags that we got passed, and if it is present, we continue
2334    * with the check above.
2335    *
2336    * if neither of these two checks yields a positive result, we just
2337    * assume that the ::allocate() virtual function that resulted in this
2338    * function being called will also allocate the children of the actor.
2339    */
2340
2341   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2342     goto check_layout;
2343
2344   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2345     goto check_layout;
2346
2347   return;
2348
2349 check_layout:
2350   if (priv->n_children != 0 &&
2351       priv->layout_manager != NULL)
2352     {
2353       ClutterContainer *container = CLUTTER_CONTAINER (self);
2354       ClutterAllocationFlags children_flags;
2355       ClutterActorBox children_box;
2356
2357       /* normalize the box passed to the layout manager */
2358       children_box.x1 = children_box.y1 = 0.f;
2359       children_box.x2 = (allocation->x2 - allocation->x1);
2360       children_box.y2 = (allocation->y2 - allocation->y1);
2361
2362       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2363        * the actor's children, since it refers only to the current
2364        * actor's allocation.
2365        */
2366       children_flags = flags;
2367       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2368
2369       CLUTTER_NOTE (LAYOUT,
2370                     "Allocating %d children of %s "
2371                     "at { %.2f, %.2f - %.2f x %.2f } "
2372                     "using %s",
2373                     priv->n_children,
2374                     _clutter_actor_get_debug_name (self),
2375                     allocation->x1,
2376                     allocation->y1,
2377                     (allocation->x2 - allocation->x1),
2378                     (allocation->y2 - allocation->y1),
2379                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2380
2381       clutter_layout_manager_allocate (priv->layout_manager,
2382                                        container,
2383                                        &children_box,
2384                                        children_flags);
2385     }
2386 }
2387
2388 static void
2389 clutter_actor_real_allocate (ClutterActor           *self,
2390                              const ClutterActorBox  *box,
2391                              ClutterAllocationFlags  flags)
2392 {
2393   ClutterActorPrivate *priv = self->priv;
2394   gboolean changed;
2395
2396   g_object_freeze_notify (G_OBJECT (self));
2397
2398   changed = clutter_actor_set_allocation_internal (self, box, flags);
2399
2400   /* we allocate our children before we notify changes in our geometry,
2401    * so that people connecting to properties will be able to get valid
2402    * data out of the sub-tree of the scene graph that has this actor at
2403    * the root.
2404    */
2405   clutter_actor_maybe_layout_children (self, box, flags);
2406
2407   if (changed)
2408     {
2409       ClutterActorBox signal_box = priv->allocation;
2410       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2411
2412       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2413                      &signal_box,
2414                      signal_flags);
2415     }
2416
2417   g_object_thaw_notify (G_OBJECT (self));
2418 }
2419
2420 static void
2421 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2422                                     ClutterActor *origin)
2423 {
2424   /* no point in queuing a redraw on a destroyed actor */
2425   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2426     return;
2427
2428   /* NB: We can't bail out early here if the actor is hidden in case
2429    * the actor bas been cloned. In this case the clone will need to
2430    * receive the signal so it can queue its own redraw.
2431    */
2432
2433   /* calls klass->queue_redraw in default handler */
2434   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2435 }
2436
2437 static void
2438 clutter_actor_real_queue_redraw (ClutterActor *self,
2439                                  ClutterActor *origin)
2440 {
2441   ClutterActor *parent;
2442
2443   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2444                 _clutter_actor_get_debug_name (self),
2445                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2446                                : "same actor");
2447
2448   /* no point in queuing a redraw on a destroyed actor */
2449   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2450     return;
2451
2452   /* If the queue redraw is coming from a child then the actor has
2453      become dirty and any queued effect is no longer valid */
2454   if (self != origin)
2455     {
2456       self->priv->is_dirty = TRUE;
2457       self->priv->effect_to_redraw = NULL;
2458     }
2459
2460   /* If the actor isn't visible, we still had to emit the signal
2461    * to allow for a ClutterClone, but the appearance of the parent
2462    * won't change so we don't have to propagate up the hierarchy.
2463    */
2464   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2465     return;
2466
2467   /* Although we could determine here that a full stage redraw
2468    * has already been queued and immediately bail out, we actually
2469    * guarantee that we will propagate a queue-redraw signal to our
2470    * parent at least once so that it's possible to implement a
2471    * container that tracks which of its children have queued a
2472    * redraw.
2473    */
2474   if (self->priv->propagated_one_redraw)
2475     {
2476       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2477       if (stage != NULL &&
2478           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2479         return;
2480     }
2481
2482   self->priv->propagated_one_redraw = TRUE;
2483
2484   /* notify parents, if they are all visible eventually we'll
2485    * queue redraw on the stage, which queues the redraw idle.
2486    */
2487   parent = clutter_actor_get_parent (self);
2488   if (parent != NULL)
2489     {
2490       /* this will go up recursively */
2491       _clutter_actor_signal_queue_redraw (parent, origin);
2492     }
2493 }
2494
2495 static void
2496 clutter_actor_real_queue_relayout (ClutterActor *self)
2497 {
2498   ClutterActorPrivate *priv = self->priv;
2499
2500   /* no point in queueing a redraw on a destroyed actor */
2501   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2502     return;
2503
2504   priv->needs_width_request  = TRUE;
2505   priv->needs_height_request = TRUE;
2506   priv->needs_allocation     = TRUE;
2507
2508   /* reset the cached size requests */
2509   memset (priv->width_requests, 0,
2510           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2511   memset (priv->height_requests, 0,
2512           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2513
2514   /* We need to go all the way up the hierarchy */
2515   if (priv->parent != NULL)
2516     _clutter_actor_queue_only_relayout (priv->parent);
2517 }
2518
2519 /**
2520  * clutter_actor_apply_relative_transform_to_point:
2521  * @self: A #ClutterActor
2522  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2523  *   default #ClutterStage
2524  * @point: A point as #ClutterVertex
2525  * @vertex: (out caller-allocates): The translated #ClutterVertex
2526  *
2527  * Transforms @point in coordinates relative to the actor into
2528  * ancestor-relative coordinates using the relevant transform
2529  * stack (i.e. scale, rotation, etc).
2530  *
2531  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2532  * this case, the coordinates returned will be the coordinates on
2533  * the stage before the projection is applied. This is different from
2534  * the behaviour of clutter_actor_apply_transform_to_point().
2535  *
2536  * Since: 0.6
2537  */
2538 void
2539 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2540                                                  ClutterActor        *ancestor,
2541                                                  const ClutterVertex *point,
2542                                                  ClutterVertex       *vertex)
2543 {
2544   gfloat w;
2545   CoglMatrix matrix;
2546
2547   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2548   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2549   g_return_if_fail (point != NULL);
2550   g_return_if_fail (vertex != NULL);
2551
2552   *vertex = *point;
2553   w = 1.0;
2554
2555   if (ancestor == NULL)
2556     ancestor = _clutter_actor_get_stage_internal (self);
2557
2558   if (ancestor == NULL)
2559     {
2560       *vertex = *point;
2561       return;
2562     }
2563
2564   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2565   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2566 }
2567
2568 static gboolean
2569 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2570                                          const ClutterVertex *vertices_in,
2571                                          ClutterVertex *vertices_out,
2572                                          int n_vertices)
2573 {
2574   ClutterActor *stage;
2575   CoglMatrix modelview;
2576   CoglMatrix projection;
2577   float viewport[4];
2578
2579   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2580
2581   stage = _clutter_actor_get_stage_internal (self);
2582
2583   /* We really can't do anything meaningful in this case so don't try
2584    * to do any transform */
2585   if (stage == NULL)
2586     return FALSE;
2587
2588   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2589    * that gets us to stage coordinates, we want to go all the way to eye
2590    * coordinates */
2591   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2592
2593   /* Fetch the projection and viewport */
2594   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2595   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2596                                &viewport[0],
2597                                &viewport[1],
2598                                &viewport[2],
2599                                &viewport[3]);
2600
2601   _clutter_util_fully_transform_vertices (&modelview,
2602                                           &projection,
2603                                           viewport,
2604                                           vertices_in,
2605                                           vertices_out,
2606                                           n_vertices);
2607
2608   return TRUE;
2609 }
2610
2611 /**
2612  * clutter_actor_apply_transform_to_point:
2613  * @self: A #ClutterActor
2614  * @point: A point as #ClutterVertex
2615  * @vertex: (out caller-allocates): The translated #ClutterVertex
2616  *
2617  * Transforms @point in coordinates relative to the actor
2618  * into screen-relative coordinates with the current actor
2619  * transformation (i.e. scale, rotation, etc)
2620  *
2621  * Since: 0.4
2622  **/
2623 void
2624 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2625                                         const ClutterVertex *point,
2626                                         ClutterVertex       *vertex)
2627 {
2628   g_return_if_fail (point != NULL);
2629   g_return_if_fail (vertex != NULL);
2630   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2631 }
2632
2633 /*
2634  * _clutter_actor_get_relative_transformation_matrix:
2635  * @self: The actor whose coordinate space you want to transform from.
2636  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2637  *            or %NULL if you want to transform all the way to eye coordinates.
2638  * @matrix: A #CoglMatrix to store the transformation
2639  *
2640  * This gets a transformation @matrix that will transform coordinates from the
2641  * coordinate space of @self into the coordinate space of @ancestor.
2642  *
2643  * For example if you need a matrix that can transform the local actor
2644  * coordinates of @self into stage coordinates you would pass the actor's stage
2645  * pointer as the @ancestor.
2646  *
2647  * If you pass %NULL then the transformation will take you all the way through
2648  * to eye coordinates. This can be useful if you want to extract the entire
2649  * modelview transform that Clutter applies before applying the projection
2650  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2651  * using cogl_set_modelview_matrix() for example then you would want a matrix
2652  * that transforms into eye coordinates.
2653  *
2654  * <note><para>This function explicitly initializes the given @matrix. If you just
2655  * want clutter to multiply a relative transformation with an existing matrix
2656  * you can use clutter_actor_apply_relative_transformation_matrix()
2657  * instead.</para></note>
2658  *
2659  */
2660 /* XXX: We should consider caching the stage relative modelview along with
2661  * the actor itself */
2662 static void
2663 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2664                                                    ClutterActor *ancestor,
2665                                                    CoglMatrix *matrix)
2666 {
2667   cogl_matrix_init_identity (matrix);
2668
2669   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2670 }
2671
2672 /* Project the given @box into stage window coordinates, writing the
2673  * transformed vertices to @verts[]. */
2674 static gboolean
2675 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2676                                           const ClutterActorBox *box,
2677                                           ClutterVertex          verts[])
2678 {
2679   ClutterVertex box_vertices[4];
2680
2681   box_vertices[0].x = box->x1;
2682   box_vertices[0].y = box->y1;
2683   box_vertices[0].z = 0;
2684   box_vertices[1].x = box->x2;
2685   box_vertices[1].y = box->y1;
2686   box_vertices[1].z = 0;
2687   box_vertices[2].x = box->x1;
2688   box_vertices[2].y = box->y2;
2689   box_vertices[2].z = 0;
2690   box_vertices[3].x = box->x2;
2691   box_vertices[3].y = box->y2;
2692   box_vertices[3].z = 0;
2693
2694   return
2695     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2696 }
2697
2698 /**
2699  * clutter_actor_get_allocation_vertices:
2700  * @self: A #ClutterActor
2701  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2702  *   against, or %NULL to use the #ClutterStage
2703  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2704  *   location for an array of 4 #ClutterVertex in which to store the result
2705  *
2706  * Calculates the transformed coordinates of the four corners of the
2707  * actor in the plane of @ancestor. The returned vertices relate to
2708  * the #ClutterActorBox coordinates as follows:
2709  * <itemizedlist>
2710  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2711  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2712  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2713  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2714  * </itemizedlist>
2715  *
2716  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2717  * this case, the coordinates returned will be the coordinates on
2718  * the stage before the projection is applied. This is different from
2719  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2720  *
2721  * Since: 0.6
2722  */
2723 void
2724 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2725                                        ClutterActor  *ancestor,
2726                                        ClutterVertex  verts[])
2727 {
2728   ClutterActorPrivate *priv;
2729   ClutterActorBox box;
2730   ClutterVertex vertices[4];
2731   CoglMatrix modelview;
2732
2733   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2734   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2735
2736   if (ancestor == NULL)
2737     ancestor = _clutter_actor_get_stage_internal (self);
2738
2739   /* Fallback to a NOP transform if the actor isn't parented under a
2740    * stage. */
2741   if (ancestor == NULL)
2742     ancestor = self;
2743
2744   priv = self->priv;
2745
2746   /* if the actor needs to be allocated we force a relayout, so that
2747    * we will have valid values to use in the transformations */
2748   if (priv->needs_allocation)
2749     {
2750       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2751       if (stage)
2752         _clutter_stage_maybe_relayout (stage);
2753       else
2754         {
2755           box.x1 = box.y1 = 0;
2756           /* The result isn't really meaningful in this case but at
2757            * least try to do something *vaguely* reasonable... */
2758           clutter_actor_get_size (self, &box.x2, &box.y2);
2759         }
2760     }
2761
2762   clutter_actor_get_allocation_box (self, &box);
2763
2764   vertices[0].x = box.x1;
2765   vertices[0].y = box.y1;
2766   vertices[0].z = 0;
2767   vertices[1].x = box.x2;
2768   vertices[1].y = box.y1;
2769   vertices[1].z = 0;
2770   vertices[2].x = box.x1;
2771   vertices[2].y = box.y2;
2772   vertices[2].z = 0;
2773   vertices[3].x = box.x2;
2774   vertices[3].y = box.y2;
2775   vertices[3].z = 0;
2776
2777   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2778                                                      &modelview);
2779
2780   cogl_matrix_transform_points (&modelview,
2781                                 3,
2782                                 sizeof (ClutterVertex),
2783                                 vertices,
2784                                 sizeof (ClutterVertex),
2785                                 vertices,
2786                                 4);
2787 }
2788
2789 /**
2790  * clutter_actor_get_abs_allocation_vertices:
2791  * @self: A #ClutterActor
2792  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2793  *   of 4 #ClutterVertex where to store the result.
2794  *
2795  * Calculates the transformed screen coordinates of the four corners of
2796  * the actor; the returned vertices relate to the #ClutterActorBox
2797  * coordinates  as follows:
2798  * <itemizedlist>
2799  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2800  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2801  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2802  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2803  * </itemizedlist>
2804  *
2805  * Since: 0.4
2806  */
2807 void
2808 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2809                                            ClutterVertex  verts[])
2810 {
2811   ClutterActorPrivate *priv;
2812   ClutterActorBox actor_space_allocation;
2813
2814   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2815
2816   priv = self->priv;
2817
2818   /* if the actor needs to be allocated we force a relayout, so that
2819    * the actor allocation box will be valid for
2820    * _clutter_actor_transform_and_project_box()
2821    */
2822   if (priv->needs_allocation)
2823     {
2824       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2825       /* There's nothing meaningful we can do now */
2826       if (!stage)
2827         return;
2828
2829       _clutter_stage_maybe_relayout (stage);
2830     }
2831
2832   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2833    * own coordinate space... */
2834   actor_space_allocation.x1 = 0;
2835   actor_space_allocation.y1 = 0;
2836   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2837   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2838   _clutter_actor_transform_and_project_box (self,
2839                                             &actor_space_allocation,
2840                                             verts);
2841 }
2842
2843 static void
2844 clutter_actor_real_apply_transform (ClutterActor *self,
2845                                     CoglMatrix   *matrix)
2846 {
2847   ClutterActorPrivate *priv = self->priv;
2848
2849   if (!priv->transform_valid)
2850     {
2851       CoglMatrix *transform = &priv->transform;
2852       const ClutterTransformInfo *info;
2853
2854       info = _clutter_actor_get_transform_info_or_defaults (self);
2855
2856       cogl_matrix_init_identity (transform);
2857
2858       cogl_matrix_translate (transform,
2859                              priv->allocation.x1,
2860                              priv->allocation.y1,
2861                              0.0);
2862
2863       if (info->depth)
2864         cogl_matrix_translate (transform, 0, 0, info->depth);
2865
2866       /*
2867        * because the rotation involves translations, we must scale
2868        * before applying the rotations (if we apply the scale after
2869        * the rotations, the translations included in the rotation are
2870        * not scaled and so the entire object will move on the screen
2871        * as a result of rotating it).
2872        */
2873       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2874         {
2875           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2876                                         &info->scale_center,
2877                                         cogl_matrix_scale (transform,
2878                                                            info->scale_x,
2879                                                            info->scale_y,
2880                                                            1.0));
2881         }
2882
2883       if (info->rz_angle)
2884         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2885                                       &info->rz_center,
2886                                       cogl_matrix_rotate (transform,
2887                                                           info->rz_angle,
2888                                                           0, 0, 1.0));
2889
2890       if (info->ry_angle)
2891         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2892                                       &info->ry_center,
2893                                       cogl_matrix_rotate (transform,
2894                                                           info->ry_angle,
2895                                                           0, 1.0, 0));
2896
2897       if (info->rx_angle)
2898         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2899                                       &info->rx_center,
2900                                       cogl_matrix_rotate (transform,
2901                                                           info->rx_angle,
2902                                                           1.0, 0, 0));
2903
2904       if (!clutter_anchor_coord_is_zero (&info->anchor))
2905         {
2906           gfloat x, y, z;
2907
2908           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2909           cogl_matrix_translate (transform, -x, -y, -z);
2910         }
2911
2912       priv->transform_valid = TRUE;
2913     }
2914
2915   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2916 }
2917
2918 /* Applies the transforms associated with this actor to the given
2919  * matrix. */
2920 void
2921 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2922                                           CoglMatrix *matrix)
2923 {
2924   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2925 }
2926
2927 /*
2928  * clutter_actor_apply_relative_transformation_matrix:
2929  * @self: The actor whose coordinate space you want to transform from.
2930  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2931  *            or %NULL if you want to transform all the way to eye coordinates.
2932  * @matrix: A #CoglMatrix to apply the transformation too.
2933  *
2934  * This multiplies a transform with @matrix that will transform coordinates
2935  * from the coordinate space of @self into the coordinate space of @ancestor.
2936  *
2937  * For example if you need a matrix that can transform the local actor
2938  * coordinates of @self into stage coordinates you would pass the actor's stage
2939  * pointer as the @ancestor.
2940  *
2941  * If you pass %NULL then the transformation will take you all the way through
2942  * to eye coordinates. This can be useful if you want to extract the entire
2943  * modelview transform that Clutter applies before applying the projection
2944  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2945  * using cogl_set_modelview_matrix() for example then you would want a matrix
2946  * that transforms into eye coordinates.
2947  *
2948  * <note>This function doesn't initialize the given @matrix, it simply
2949  * multiplies the requested transformation matrix with the existing contents of
2950  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2951  * before calling this function, or you can use
2952  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2953  */
2954 void
2955 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2956                                                      ClutterActor *ancestor,
2957                                                      CoglMatrix *matrix)
2958 {
2959   ClutterActor *parent;
2960
2961   /* Note we terminate before ever calling stage->apply_transform()
2962    * since that would conceptually be relative to the underlying
2963    * window OpenGL coordinates so we'd need a special @ancestor
2964    * value to represent the fake parent of the stage. */
2965   if (self == ancestor)
2966     return;
2967
2968   parent = clutter_actor_get_parent (self);
2969
2970   if (parent != NULL)
2971     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2972                                                          matrix);
2973
2974   _clutter_actor_apply_modelview_transform (self, matrix);
2975 }
2976
2977 static void
2978 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2979                                        ClutterPaintVolume *pv,
2980                                        const char *label,
2981                                        const CoglColor *color)
2982 {
2983   static CoglPipeline *outline = NULL;
2984   CoglPrimitive *prim;
2985   ClutterVertex line_ends[12 * 2];
2986   int n_vertices;
2987   CoglContext *ctx =
2988     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2989   /* XXX: at some point we'll query this from the stage but we can't
2990    * do that until the osx backend uses Cogl natively. */
2991   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2992
2993   if (outline == NULL)
2994     outline = cogl_pipeline_new (ctx);
2995
2996   _clutter_paint_volume_complete (pv);
2997
2998   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2999
3000   /* Front face */
3001   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
3002   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
3003   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
3004   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
3005
3006   if (!pv->is_2d)
3007     {
3008       /* Back face */
3009       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
3010       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
3011       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
3012       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
3013
3014       /* Lines connecting front face to back face */
3015       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
3016       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
3017       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3018       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3019     }
3020
3021   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3022                                 n_vertices,
3023                                 (CoglVertexP3 *)line_ends);
3024
3025   cogl_pipeline_set_color (outline, color);
3026   cogl_framebuffer_draw_primitive (fb, outline, prim);
3027   cogl_object_unref (prim);
3028
3029   if (label)
3030     {
3031       PangoLayout *layout;
3032       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3033       pango_layout_set_text (layout, label, -1);
3034       cogl_pango_render_layout (layout,
3035                                 pv->vertices[0].x,
3036                                 pv->vertices[0].y,
3037                                 color,
3038                                 0);
3039       g_object_unref (layout);
3040     }
3041 }
3042
3043 static void
3044 _clutter_actor_draw_paint_volume (ClutterActor *self)
3045 {
3046   ClutterPaintVolume *pv;
3047   CoglColor color;
3048
3049   pv = _clutter_actor_get_paint_volume_mutable (self);
3050   if (!pv)
3051     {
3052       gfloat width, height;
3053       ClutterPaintVolume fake_pv;
3054
3055       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3056       _clutter_paint_volume_init_static (&fake_pv, stage);
3057
3058       clutter_actor_get_size (self, &width, &height);
3059       clutter_paint_volume_set_width (&fake_pv, width);
3060       clutter_paint_volume_set_height (&fake_pv, height);
3061
3062       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3063       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3064                                              _clutter_actor_get_debug_name (self),
3065                                              &color);
3066
3067       clutter_paint_volume_free (&fake_pv);
3068     }
3069   else
3070     {
3071       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3072       _clutter_actor_draw_paint_volume_full (self, pv,
3073                                              _clutter_actor_get_debug_name (self),
3074                                              &color);
3075     }
3076 }
3077
3078 static void
3079 _clutter_actor_paint_cull_result (ClutterActor *self,
3080                                   gboolean success,
3081                                   ClutterCullResult result)
3082 {
3083   ClutterPaintVolume *pv;
3084   CoglColor color;
3085
3086   if (success)
3087     {
3088       if (result == CLUTTER_CULL_RESULT_IN)
3089         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3090       else if (result == CLUTTER_CULL_RESULT_OUT)
3091         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3092       else
3093         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3094     }
3095   else
3096     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3097
3098   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3099     _clutter_actor_draw_paint_volume_full (self, pv,
3100                                            _clutter_actor_get_debug_name (self),
3101                                            &color);
3102   else
3103     {
3104       PangoLayout *layout;
3105       char *label =
3106         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3107       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3108       cogl_set_source_color (&color);
3109
3110       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3111       pango_layout_set_text (layout, label, -1);
3112       cogl_pango_render_layout (layout,
3113                                 0,
3114                                 0,
3115                                 &color,
3116                                 0);
3117       g_free (label);
3118       g_object_unref (layout);
3119     }
3120 }
3121
3122 static int clone_paint_level = 0;
3123
3124 void
3125 _clutter_actor_push_clone_paint (void)
3126 {
3127   clone_paint_level++;
3128 }
3129
3130 void
3131 _clutter_actor_pop_clone_paint (void)
3132 {
3133   clone_paint_level--;
3134 }
3135
3136 static gboolean
3137 in_clone_paint (void)
3138 {
3139   return clone_paint_level > 0;
3140 }
3141
3142 /* Returns TRUE if the actor can be ignored */
3143 /* FIXME: we should return a ClutterCullResult, and
3144  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3145  * means there's no point in trying to cull descendants of the current
3146  * node. */
3147 static gboolean
3148 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3149 {
3150   ClutterActorPrivate *priv = self->priv;
3151   ClutterActor *stage;
3152   const ClutterPlane *stage_clip;
3153
3154   if (!priv->last_paint_volume_valid)
3155     {
3156       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3157                     "->last_paint_volume_valid == FALSE",
3158                     _clutter_actor_get_debug_name (self));
3159       return FALSE;
3160     }
3161
3162   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3163     return FALSE;
3164
3165   stage = _clutter_actor_get_stage_internal (self);
3166   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3167   if (G_UNLIKELY (!stage_clip))
3168     {
3169       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3170                     "No stage clip set",
3171                     _clutter_actor_get_debug_name (self));
3172       return FALSE;
3173     }
3174
3175   if (cogl_get_draw_framebuffer () !=
3176       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3177     {
3178       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3179                     "Current framebuffer doesn't correspond to stage",
3180                     _clutter_actor_get_debug_name (self));
3181       return FALSE;
3182     }
3183
3184   *result_out =
3185     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3186   return TRUE;
3187 }
3188
3189 static void
3190 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3191 {
3192   ClutterActorPrivate *priv = self->priv;
3193   const ClutterPaintVolume *pv;
3194
3195   if (priv->last_paint_volume_valid)
3196     {
3197       clutter_paint_volume_free (&priv->last_paint_volume);
3198       priv->last_paint_volume_valid = FALSE;
3199     }
3200
3201   pv = clutter_actor_get_paint_volume (self);
3202   if (!pv)
3203     {
3204       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3205                     "Actor failed to report a paint volume",
3206                     _clutter_actor_get_debug_name (self));
3207       return;
3208     }
3209
3210   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3211
3212   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3213                                             NULL); /* eye coordinates */
3214
3215   priv->last_paint_volume_valid = TRUE;
3216 }
3217
3218 static inline gboolean
3219 actor_has_shader_data (ClutterActor *self)
3220 {
3221   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3222 }
3223
3224 guint32
3225 _clutter_actor_get_pick_id (ClutterActor *self)
3226 {
3227   if (self->priv->pick_id < 0)
3228     return 0;
3229
3230   return self->priv->pick_id;
3231 }
3232
3233 /* This is the same as clutter_actor_add_effect except that it doesn't
3234    queue a redraw and it doesn't notify on the effect property */
3235 static void
3236 _clutter_actor_add_effect_internal (ClutterActor  *self,
3237                                     ClutterEffect *effect)
3238 {
3239   ClutterActorPrivate *priv = self->priv;
3240
3241   if (priv->effects == NULL)
3242     {
3243       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3244       priv->effects->actor = self;
3245     }
3246
3247   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3248 }
3249
3250 /* This is the same as clutter_actor_remove_effect except that it doesn't
3251    queue a redraw and it doesn't notify on the effect property */
3252 static void
3253 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3254                                        ClutterEffect *effect)
3255 {
3256   ClutterActorPrivate *priv = self->priv;
3257
3258   if (priv->effects == NULL)
3259     return;
3260
3261   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3262
3263   if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3264     g_clear_object (&priv->effects);
3265 }
3266
3267 static gboolean
3268 needs_flatten_effect (ClutterActor *self)
3269 {
3270   ClutterActorPrivate *priv = self->priv;
3271
3272   if (G_UNLIKELY (clutter_paint_debug_flags &
3273                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3274     return FALSE;
3275
3276   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3277     return TRUE;
3278   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3279     {
3280       if (clutter_actor_get_paint_opacity (self) < 255 &&
3281           clutter_actor_has_overlaps (self))
3282         return TRUE;
3283     }
3284
3285   return FALSE;
3286 }
3287
3288 static void
3289 add_or_remove_flatten_effect (ClutterActor *self)
3290 {
3291   ClutterActorPrivate *priv = self->priv;
3292
3293   /* Add or remove the flatten effect depending on the
3294      offscreen-redirect property. */
3295   if (needs_flatten_effect (self))
3296     {
3297       if (priv->flatten_effect == NULL)
3298         {
3299           ClutterActorMeta *actor_meta;
3300           gint priority;
3301
3302           priv->flatten_effect = _clutter_flatten_effect_new ();
3303           /* Keep a reference to the effect so that we can queue
3304              redraws from it */
3305           g_object_ref_sink (priv->flatten_effect);
3306
3307           /* Set the priority of the effect to high so that it will
3308              always be applied to the actor first. It uses an internal
3309              priority so that it won't be visible to applications */
3310           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3311           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3312           _clutter_actor_meta_set_priority (actor_meta, priority);
3313
3314           /* This will add the effect without queueing a redraw */
3315           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3316         }
3317     }
3318   else
3319     {
3320       if (priv->flatten_effect != NULL)
3321         {
3322           /* Destroy the effect so that it will lose its fbo cache of
3323              the actor */
3324           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3325           g_clear_object (&priv->flatten_effect);
3326         }
3327     }
3328 }
3329
3330 static void
3331 clutter_actor_real_paint (ClutterActor *actor)
3332 {
3333   ClutterActorPrivate *priv = actor->priv;
3334   ClutterActor *iter;
3335
3336   for (iter = priv->first_child;
3337        iter != NULL;
3338        iter = iter->priv->next_sibling)
3339     {
3340       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3341                     _clutter_actor_get_debug_name (iter),
3342                     _clutter_actor_get_debug_name (actor),
3343                     iter->priv->allocation.x1,
3344                     iter->priv->allocation.y1,
3345                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3346                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3347
3348       clutter_actor_paint (iter);
3349     }
3350 }
3351
3352 static gboolean
3353 clutter_actor_paint_node (ClutterActor     *actor,
3354                           ClutterPaintNode *root)
3355 {
3356   ClutterActorPrivate *priv = actor->priv;
3357
3358   if (root == NULL)
3359     return FALSE;
3360
3361   if (priv->bg_color_set &&
3362       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3363     {
3364       ClutterPaintNode *node;
3365       ClutterColor bg_color;
3366       ClutterActorBox box;
3367
3368       box.x1 = 0.f;
3369       box.y1 = 0.f;
3370       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3371       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3372
3373       bg_color = priv->bg_color;
3374       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3375                      * priv->bg_color.alpha
3376                      / 255;
3377
3378       node = clutter_color_node_new (&bg_color);
3379       clutter_paint_node_set_name (node, "backgroundColor");
3380       clutter_paint_node_add_rectangle (node, &box);
3381       clutter_paint_node_add_child (root, node);
3382       clutter_paint_node_unref (node);
3383     }
3384
3385   if (priv->content != NULL)
3386     _clutter_content_paint_content (priv->content, actor, root);
3387
3388   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3389     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3390
3391   if (clutter_paint_node_get_n_children (root) == 0)
3392     return FALSE;
3393
3394 #ifdef CLUTTER_ENABLE_DEBUG
3395   if (CLUTTER_HAS_DEBUG (PAINT))
3396     {
3397       /* dump the tree only if we have one */
3398       _clutter_paint_node_dump_tree (root);
3399     }
3400 #endif /* CLUTTER_ENABLE_DEBUG */
3401
3402   _clutter_paint_node_paint (root);
3403
3404 #if 0
3405   /* XXX: Uncomment this when we disable emitting the paint signal */
3406   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3407 #endif
3408
3409   return TRUE;
3410 }
3411
3412 /**
3413  * clutter_actor_paint:
3414  * @self: A #ClutterActor
3415  *
3416  * Renders the actor to display.
3417  *
3418  * This function should not be called directly by applications.
3419  * Call clutter_actor_queue_redraw() to queue paints, instead.
3420  *
3421  * This function is context-aware, and will either cause a
3422  * regular paint or a pick paint.
3423  *
3424  * This function will emit the #ClutterActor::paint signal or
3425  * the #ClutterActor::pick signal, depending on the context.
3426  *
3427  * This function does not paint the actor if the actor is set to 0,
3428  * unless it is performing a pick paint.
3429  */
3430 void
3431 clutter_actor_paint (ClutterActor *self)
3432 {
3433   ClutterActorPrivate *priv;
3434   ClutterPickMode pick_mode;
3435   gboolean clip_set = FALSE;
3436   gboolean shader_applied = FALSE;
3437
3438   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3439                           "Actor real-paint counter",
3440                           "Increments each time any actor is painted",
3441                           0 /* no application private data */);
3442   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3443                           "Actor pick-paint counter",
3444                           "Increments each time any actor is painted "
3445                           "for picking",
3446                           0 /* no application private data */);
3447
3448   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3449
3450   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3451     return;
3452
3453   priv = self->priv;
3454
3455   pick_mode = _clutter_context_get_pick_mode ();
3456
3457   if (pick_mode == CLUTTER_PICK_NONE)
3458     priv->propagated_one_redraw = FALSE;
3459
3460   /* It's an important optimization that we consider painting of
3461    * actors with 0 opacity to be a NOP... */
3462   if (pick_mode == CLUTTER_PICK_NONE &&
3463       /* ignore top-levels, since they might be transparent */
3464       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3465       /* Use the override opacity if its been set */
3466       ((priv->opacity_override >= 0) ?
3467        priv->opacity_override : priv->opacity) == 0)
3468     return;
3469
3470   /* if we aren't paintable (not in a toplevel with all
3471    * parents paintable) then do nothing.
3472    */
3473   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3474     return;
3475
3476   /* mark that we are in the paint process */
3477   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3478
3479   cogl_push_matrix();
3480
3481   if (priv->enable_model_view_transform)
3482     {
3483       CoglMatrix matrix;
3484
3485       /* XXX: It could be better to cache the modelview with the actor
3486        * instead of progressively building up the transformations on
3487        * the matrix stack every time we paint. */
3488       cogl_get_modelview_matrix (&matrix);
3489       _clutter_actor_apply_modelview_transform (self, &matrix);
3490
3491 #ifdef CLUTTER_ENABLE_DEBUG
3492       /* Catch when out-of-band transforms have been made by actors not as part
3493        * of an apply_transform vfunc... */
3494       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3495         {
3496           CoglMatrix expected_matrix;
3497
3498           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3499                                                              &expected_matrix);
3500
3501           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3502             {
3503               GString *buf = g_string_sized_new (1024);
3504               ClutterActor *parent;
3505
3506               parent = self;
3507               while (parent != NULL)
3508                 {
3509                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3510
3511                   if (parent->priv->parent != NULL)
3512                     g_string_append (buf, "->");
3513
3514                   parent = parent->priv->parent;
3515                 }
3516
3517               g_warning ("Unexpected transform found when painting actor "
3518                          "\"%s\". This will be caused by one of the actor's "
3519                          "ancestors (%s) using the Cogl API directly to transform "
3520                          "children instead of using ::apply_transform().",
3521                          _clutter_actor_get_debug_name (self),
3522                          buf->str);
3523
3524               g_string_free (buf, TRUE);
3525             }
3526         }
3527 #endif /* CLUTTER_ENABLE_DEBUG */
3528
3529       cogl_set_modelview_matrix (&matrix);
3530     }
3531
3532   if (priv->has_clip)
3533     {
3534       cogl_clip_push_rectangle (priv->clip.x,
3535                                 priv->clip.y,
3536                                 priv->clip.x + priv->clip.width,
3537                                 priv->clip.y + priv->clip.height);
3538       clip_set = TRUE;
3539     }
3540   else if (priv->clip_to_allocation)
3541     {
3542       gfloat width, height;
3543
3544       width  = priv->allocation.x2 - priv->allocation.x1;
3545       height = priv->allocation.y2 - priv->allocation.y1;
3546
3547       cogl_clip_push_rectangle (0, 0, width, height);
3548       clip_set = TRUE;
3549     }
3550
3551   if (pick_mode == CLUTTER_PICK_NONE)
3552     {
3553       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3554
3555       /* We check whether we need to add the flatten effect before
3556          each paint so that we can avoid having a mechanism for
3557          applications to notify when the value of the
3558          has_overlaps virtual changes. */
3559       add_or_remove_flatten_effect (self);
3560     }
3561   else
3562     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3563
3564   /* We save the current paint volume so that the next time the
3565    * actor queues a redraw we can constrain the redraw to just
3566    * cover the union of the new bounding box and the old.
3567    *
3568    * We also fetch the current paint volume to perform culling so
3569    * we can avoid painting actors outside the current clip region.
3570    *
3571    * If we are painting inside a clone, we should neither update
3572    * the paint volume or use it to cull painting, since the paint
3573    * box represents the location of the source actor on the
3574    * screen.
3575    *
3576    * XXX: We are starting to do a lot of vertex transforms on
3577    * the CPU in a typical paint, so at some point we should
3578    * audit these and consider caching some things.
3579    *
3580    * NB: We don't perform culling while picking at this point because
3581    * clutter-stage.c doesn't setup the clipping planes appropriately.
3582    *
3583    * NB: We don't want to update the last-paint-volume during picking
3584    * because the last-paint-volume is used to determine the old screen
3585    * space location of an actor that has moved so we can know the
3586    * minimal region to redraw to clear an old view of the actor. If we
3587    * update this during picking then by the time we come around to
3588    * paint then the last-paint-volume would likely represent the new
3589    * actor position not the old.
3590    */
3591   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3592     {
3593       gboolean success;
3594       /* annoyingly gcc warns if uninitialized even though
3595        * the initialization is redundant :-( */
3596       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3597
3598       if (G_LIKELY ((clutter_paint_debug_flags &
3599                      (CLUTTER_DEBUG_DISABLE_CULLING |
3600                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3601                     (CLUTTER_DEBUG_DISABLE_CULLING |
3602                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3603         _clutter_actor_update_last_paint_volume (self);
3604
3605       success = cull_actor (self, &result);
3606
3607       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3608         _clutter_actor_paint_cull_result (self, success, result);
3609       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3610         goto done;
3611     }
3612
3613   if (priv->effects == NULL)
3614     {
3615       if (pick_mode == CLUTTER_PICK_NONE &&
3616           actor_has_shader_data (self))
3617         {
3618           _clutter_actor_shader_pre_paint (self, FALSE);
3619           shader_applied = TRUE;
3620         }
3621
3622       priv->next_effect_to_paint = NULL;
3623     }
3624   else
3625     priv->next_effect_to_paint =
3626       _clutter_meta_group_peek_metas (priv->effects);
3627
3628   clutter_actor_continue_paint (self);
3629
3630   if (shader_applied)
3631     _clutter_actor_shader_post_paint (self);
3632
3633   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3634                   pick_mode == CLUTTER_PICK_NONE))
3635     _clutter_actor_draw_paint_volume (self);
3636
3637 done:
3638   /* If we make it here then the actor has run through a complete
3639      paint run including all the effects so it's no longer dirty */
3640   if (pick_mode == CLUTTER_PICK_NONE)
3641     priv->is_dirty = FALSE;
3642
3643   if (clip_set)
3644     cogl_clip_pop();
3645
3646   cogl_pop_matrix();
3647
3648   /* paint sequence complete */
3649   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3650 }
3651
3652 /**
3653  * clutter_actor_continue_paint:
3654  * @self: A #ClutterActor
3655  *
3656  * Run the next stage of the paint sequence. This function should only
3657  * be called within the implementation of the ‘run’ virtual of a
3658  * #ClutterEffect. It will cause the run method of the next effect to
3659  * be applied, or it will paint the actual actor if the current effect
3660  * is the last effect in the chain.
3661  *
3662  * Since: 1.8
3663  */
3664 void
3665 clutter_actor_continue_paint (ClutterActor *self)
3666 {
3667   ClutterActorPrivate *priv;
3668
3669   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3670   /* This should only be called from with in the ‘run’ implementation
3671      of a ClutterEffect */
3672   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3673
3674   priv = self->priv;
3675
3676   /* Skip any effects that are disabled */
3677   while (priv->next_effect_to_paint &&
3678          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3679     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3680
3681   /* If this has come from the last effect then we'll just paint the
3682      actual actor */
3683   if (priv->next_effect_to_paint == NULL)
3684     {
3685       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3686         {
3687           ClutterPaintNode *dummy;
3688
3689           /* XXX - this will go away in 2.0, when we can get rid of this
3690            * stuff and switch to a pure retained render tree of PaintNodes
3691            * for the entire frame, starting from the Stage; the paint()
3692            * virtual function can then be called directly.
3693            */
3694           dummy = _clutter_dummy_node_new (self);
3695           clutter_paint_node_set_name (dummy, "Root");
3696
3697           /* XXX - for 1.12, we use the return value of paint_node() to
3698            * decide whether we should emit the ::paint signal.
3699            */
3700           clutter_actor_paint_node (self, dummy);
3701           clutter_paint_node_unref (dummy);
3702
3703           g_signal_emit (self, actor_signals[PAINT], 0);
3704         }
3705       else
3706         {
3707           ClutterColor col = { 0, };
3708
3709           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3710
3711           /* Actor will then paint silhouette of itself in supplied
3712            * color.  See clutter_stage_get_actor_at_pos() for where
3713            * picking is enabled.
3714            */
3715           g_signal_emit (self, actor_signals[PICK], 0, &col);
3716         }
3717     }
3718   else
3719     {
3720       ClutterEffect *old_current_effect;
3721       ClutterEffectPaintFlags run_flags = 0;
3722
3723       /* Cache the current effect so that we can put it back before
3724          returning */
3725       old_current_effect = priv->current_effect;
3726
3727       priv->current_effect = priv->next_effect_to_paint->data;
3728       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3729
3730       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3731         {
3732           if (priv->is_dirty)
3733             {
3734               /* If there's an effect queued with this redraw then all
3735                  effects up to that one will be considered dirty. It
3736                  is expected the queued effect will paint the cached
3737                  image and not call clutter_actor_continue_paint again
3738                  (although it should work ok if it does) */
3739               if (priv->effect_to_redraw == NULL ||
3740                   priv->current_effect != priv->effect_to_redraw)
3741                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3742             }
3743
3744           _clutter_effect_paint (priv->current_effect, run_flags);
3745         }
3746       else
3747         {
3748           /* We can't determine when an actor has been modified since
3749              its last pick so lets just assume it has always been
3750              modified */
3751           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3752
3753           _clutter_effect_pick (priv->current_effect, run_flags);
3754         }
3755
3756       priv->current_effect = old_current_effect;
3757     }
3758 }
3759
3760 static ClutterActorTraverseVisitFlags
3761 invalidate_queue_redraw_entry (ClutterActor *self,
3762                                int           depth,
3763                                gpointer      user_data)
3764 {
3765   ClutterActorPrivate *priv = self->priv;
3766
3767   if (priv->queue_redraw_entry != NULL)
3768     {
3769       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3770       priv->queue_redraw_entry = NULL;
3771     }
3772
3773   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3774 }
3775
3776 static inline void
3777 remove_child (ClutterActor *self,
3778               ClutterActor *child)
3779 {
3780   ClutterActor *prev_sibling, *next_sibling;
3781
3782   prev_sibling = child->priv->prev_sibling;
3783   next_sibling = child->priv->next_sibling;
3784
3785   if (prev_sibling != NULL)
3786     prev_sibling->priv->next_sibling = next_sibling;
3787
3788   if (next_sibling != NULL)
3789     next_sibling->priv->prev_sibling = prev_sibling;
3790
3791   if (self->priv->first_child == child)
3792     self->priv->first_child = next_sibling;
3793
3794   if (self->priv->last_child == child)
3795     self->priv->last_child = prev_sibling;
3796
3797   child->priv->parent = NULL;
3798   child->priv->prev_sibling = NULL;
3799   child->priv->next_sibling = NULL;
3800 }
3801
3802 typedef enum {
3803   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3804   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3805   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3806   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3807   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3808   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3809
3810   /* default flags for public API */
3811   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3812                                     REMOVE_CHILD_EMIT_PARENT_SET |
3813                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3814                                     REMOVE_CHILD_CHECK_STATE |
3815                                     REMOVE_CHILD_FLUSH_QUEUE |
3816                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3817
3818   /* flags for legacy/deprecated API */
3819   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3820                                     REMOVE_CHILD_FLUSH_QUEUE |
3821                                     REMOVE_CHILD_EMIT_PARENT_SET |
3822                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3823 } ClutterActorRemoveChildFlags;
3824
3825 /*< private >
3826  * clutter_actor_remove_child_internal:
3827  * @self: a #ClutterActor
3828  * @child: the child of @self that has to be removed
3829  * @flags: control the removal operations
3830  *
3831  * Removes @child from the list of children of @self.
3832  */
3833 static void
3834 clutter_actor_remove_child_internal (ClutterActor                 *self,
3835                                      ClutterActor                 *child,
3836                                      ClutterActorRemoveChildFlags  flags)
3837 {
3838   ClutterActor *old_first, *old_last;
3839   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3840   gboolean flush_queue;
3841   gboolean notify_first_last;
3842   gboolean was_mapped;
3843
3844   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3845   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3846   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3847   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3848   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3849   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3850
3851   g_object_freeze_notify (G_OBJECT (self));
3852
3853   if (destroy_meta)
3854     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3855
3856   if (check_state)
3857     {
3858       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3859
3860       /* we need to unrealize *before* we set parent_actor to NULL,
3861        * because in an unrealize method actors are dissociating from the
3862        * stage, which means they need to be able to
3863        * clutter_actor_get_stage().
3864        *
3865        * yhis should unmap and unrealize, unless we're reparenting.
3866        */
3867       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3868     }
3869   else
3870     was_mapped = FALSE;
3871
3872   if (flush_queue)
3873     {
3874       /* We take this opportunity to invalidate any queue redraw entry
3875        * associated with the actor and descendants since we won't be able to
3876        * determine the appropriate stage after this.
3877        *
3878        * we do this after we updated the mapped state because actors might
3879        * end up queueing redraws inside their mapped/unmapped virtual
3880        * functions, and if we invalidate the redraw entry we could end up
3881        * with an inconsistent state and weird memory corruption. see
3882        * bugs:
3883        *
3884        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3885        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3886        */
3887       _clutter_actor_traverse (child,
3888                                0,
3889                                invalidate_queue_redraw_entry,
3890                                NULL,
3891                                NULL);
3892     }
3893
3894   old_first = self->priv->first_child;
3895   old_last = self->priv->last_child;
3896
3897   remove_child (self, child);
3898
3899   self->priv->n_children -= 1;
3900
3901   self->priv->age += 1;
3902
3903   /* clutter_actor_reparent() will emit ::parent-set for us */
3904   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3905     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3906
3907   /* if the child was mapped then we need to relayout ourselves to account
3908    * for the removed child
3909    */
3910   if (was_mapped)
3911     clutter_actor_queue_relayout (self);
3912
3913   /* we need to emit the signal before dropping the reference */
3914   if (emit_actor_removed)
3915     g_signal_emit_by_name (self, "actor-removed", child);
3916
3917   if (notify_first_last)
3918     {
3919       if (old_first != self->priv->first_child)
3920         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3921
3922       if (old_last != self->priv->last_child)
3923         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3924     }
3925
3926   g_object_thaw_notify (G_OBJECT (self));
3927
3928   /* remove the reference we acquired in clutter_actor_add_child() */
3929   g_object_unref (child);
3930 }
3931
3932 static const ClutterTransformInfo default_transform_info = {
3933   0.0, { 0, },          /* rotation-x */
3934   0.0, { 0, },          /* rotation-y */
3935   0.0, { 0, },          /* rotation-z */
3936
3937   1.0, 1.0, { 0, },     /* scale */
3938
3939   { 0, },               /* anchor */
3940
3941   0.0,                  /* depth */
3942 };
3943
3944 /*< private >
3945  * _clutter_actor_get_transform_info_or_defaults:
3946  * @self: a #ClutterActor
3947  *
3948  * Retrieves the ClutterTransformInfo structure associated to an actor.
3949  *
3950  * If the actor does not have a ClutterTransformInfo structure associated
3951  * to it, then the default structure will be returned.
3952  *
3953  * This function should only be used for getters.
3954  *
3955  * Return value: a const pointer to the ClutterTransformInfo structure
3956  */
3957 const ClutterTransformInfo *
3958 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3959 {
3960   ClutterTransformInfo *info;
3961
3962   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3963   if (info != NULL)
3964     return info;
3965
3966   return &default_transform_info;
3967 }
3968
3969 static void
3970 clutter_transform_info_free (gpointer data)
3971 {
3972   if (data != NULL)
3973     g_slice_free (ClutterTransformInfo, data);
3974 }
3975
3976 /*< private >
3977  * _clutter_actor_get_transform_info:
3978  * @self: a #ClutterActor
3979  *
3980  * Retrieves a pointer to the ClutterTransformInfo structure.
3981  *
3982  * If the actor does not have a ClutterTransformInfo associated to it, one
3983  * will be created and initialized to the default values.
3984  *
3985  * This function should be used for setters.
3986  *
3987  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3988  * instead.
3989  *
3990  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3991  *   structure
3992  */
3993 ClutterTransformInfo *
3994 _clutter_actor_get_transform_info (ClutterActor *self)
3995 {
3996   ClutterTransformInfo *info;
3997
3998   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3999   if (info == NULL)
4000     {
4001       info = g_slice_new (ClutterTransformInfo);
4002
4003       *info = default_transform_info;
4004
4005       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
4006                                info,
4007                                clutter_transform_info_free);
4008     }
4009
4010   return info;
4011 }
4012
4013 /*< private >
4014  * clutter_actor_set_rotation_angle_internal:
4015  * @self: a #ClutterActor
4016  * @axis: the axis of the angle to change
4017  * @angle: the angle of rotation
4018  *
4019  * Sets the rotation angle on the given axis without affecting the
4020  * rotation center point.
4021  */
4022 static inline void
4023 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
4024                                            ClutterRotateAxis  axis,
4025                                            gdouble            angle)
4026 {
4027   GObject *obj = G_OBJECT (self);
4028   ClutterTransformInfo *info;
4029
4030   info = _clutter_actor_get_transform_info (self);
4031
4032   g_object_freeze_notify (obj);
4033
4034   switch (axis)
4035     {
4036     case CLUTTER_X_AXIS:
4037       info->rx_angle = angle;
4038       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4039       break;
4040
4041     case CLUTTER_Y_AXIS:
4042       info->ry_angle = angle;
4043       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4044       break;
4045
4046     case CLUTTER_Z_AXIS:
4047       info->rz_angle = angle;
4048       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4049       break;
4050     }
4051
4052   self->priv->transform_valid = FALSE;
4053
4054   g_object_thaw_notify (obj);
4055
4056   clutter_actor_queue_redraw (self);
4057 }
4058
4059 static inline void
4060 clutter_actor_set_rotation_angle (ClutterActor      *self,
4061                                   ClutterRotateAxis  axis,
4062                                   gdouble            angle)
4063 {
4064   const ClutterTransformInfo *info;
4065   const double *cur_angle_p = NULL;
4066   GParamSpec *pspec = NULL;
4067
4068   info = _clutter_actor_get_transform_info_or_defaults (self);
4069
4070   switch (axis)
4071     {
4072     case CLUTTER_X_AXIS:
4073       cur_angle_p = &info->rx_angle;
4074       pspec = obj_props[PROP_ROTATION_ANGLE_X];
4075       break;
4076
4077     case CLUTTER_Y_AXIS:
4078       cur_angle_p = &info->ry_angle;
4079       pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4080       break;
4081
4082     case CLUTTER_Z_AXIS:
4083       cur_angle_p = &info->rz_angle;
4084       pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4085       break;
4086     }
4087
4088   g_assert (pspec != NULL);
4089   g_assert (cur_angle_p != NULL);
4090
4091   if (_clutter_actor_get_transition (self, pspec) == NULL)
4092     _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4093   else
4094     _clutter_actor_update_transition (self, pspec, angle);
4095
4096   clutter_actor_queue_redraw (self);
4097 }
4098
4099 /*< private >
4100  * clutter_actor_set_rotation_center_internal:
4101  * @self: a #ClutterActor
4102  * @axis: the axis of the center to change
4103  * @center: the coordinates of the rotation center
4104  *
4105  * Sets the rotation center on the given axis without affecting the
4106  * rotation angle.
4107  */
4108 static inline void
4109 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4110                                             ClutterRotateAxis    axis,
4111                                             const ClutterVertex *center)
4112 {
4113   GObject *obj = G_OBJECT (self);
4114   ClutterTransformInfo *info;
4115   ClutterVertex v = { 0, 0, 0 };
4116
4117   info = _clutter_actor_get_transform_info (self);
4118
4119   if (center != NULL)
4120     v = *center;
4121
4122   g_object_freeze_notify (obj);
4123
4124   switch (axis)
4125     {
4126     case CLUTTER_X_AXIS:
4127       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4128       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4129       break;
4130
4131     case CLUTTER_Y_AXIS:
4132       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4133       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4134       break;
4135
4136     case CLUTTER_Z_AXIS:
4137       /* if the previously set rotation center was fractional, then
4138        * setting explicit coordinates will have to notify the
4139        * :rotation-center-z-gravity property as well
4140        */
4141       if (info->rz_center.is_fractional)
4142         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4143
4144       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4145       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4146       break;
4147     }
4148
4149   self->priv->transform_valid = FALSE;
4150
4151   g_object_thaw_notify (obj);
4152
4153   clutter_actor_queue_redraw (self);
4154 }
4155
4156 static void
4157 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4158                                          double factor,
4159                                          GParamSpec *pspec)
4160 {
4161   GObject *obj = G_OBJECT (self);
4162   ClutterTransformInfo *info;
4163
4164   info = _clutter_actor_get_transform_info (self);
4165
4166   if (pspec == obj_props[PROP_SCALE_X])
4167     info->scale_x = factor;
4168   else
4169     info->scale_y = factor;
4170
4171   self->priv->transform_valid = FALSE;
4172   clutter_actor_queue_redraw (self);
4173   g_object_notify_by_pspec (obj, pspec);
4174 }
4175
4176 static inline void
4177 clutter_actor_set_scale_factor (ClutterActor      *self,
4178                                 ClutterRotateAxis  axis,
4179                                 gdouble            factor)
4180 {
4181   const ClutterTransformInfo *info;
4182   const double *scale_p = NULL;
4183   GParamSpec *pspec = NULL;
4184
4185   info = _clutter_actor_get_transform_info_or_defaults (self);
4186
4187   switch (axis)
4188     {
4189     case CLUTTER_X_AXIS:
4190       pspec = obj_props[PROP_SCALE_X];
4191       scale_p = &info->scale_x;
4192       break;
4193
4194     case CLUTTER_Y_AXIS:
4195       pspec = obj_props[PROP_SCALE_Y];
4196       scale_p = &info->scale_y;
4197       break;
4198
4199     case CLUTTER_Z_AXIS:
4200       break;
4201     }
4202
4203   g_assert (pspec != NULL);
4204   g_assert (scale_p != NULL);
4205
4206   if (_clutter_actor_get_transition (self, pspec) == NULL)
4207     _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4208   else
4209     _clutter_actor_update_transition (self, pspec, factor);
4210
4211   clutter_actor_queue_redraw (self);
4212 }
4213
4214 static inline void
4215 clutter_actor_set_scale_center (ClutterActor      *self,
4216                                 ClutterRotateAxis  axis,
4217                                 gfloat             coord)
4218 {
4219   GObject *obj = G_OBJECT (self);
4220   ClutterTransformInfo *info;
4221   gfloat center_x, center_y;
4222
4223   info = _clutter_actor_get_transform_info (self);
4224
4225   g_object_freeze_notify (obj);
4226
4227   /* get the current scale center coordinates */
4228   clutter_anchor_coord_get_units (self, &info->scale_center,
4229                                   &center_x,
4230                                   &center_y,
4231                                   NULL);
4232
4233   /* we need to notify this too, because setting explicit coordinates will
4234    * change the gravity as a side effect
4235    */
4236   if (info->scale_center.is_fractional)
4237     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4238
4239   switch (axis)
4240     {
4241     case CLUTTER_X_AXIS:
4242       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4243       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4244       break;
4245
4246     case CLUTTER_Y_AXIS:
4247       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4248       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4249       break;
4250
4251     default:
4252       g_assert_not_reached ();
4253     }
4254
4255   self->priv->transform_valid = FALSE;
4256
4257   clutter_actor_queue_redraw (self);
4258
4259   g_object_thaw_notify (obj);
4260 }
4261
4262 static inline void
4263 clutter_actor_set_scale_gravity (ClutterActor   *self,
4264                                  ClutterGravity  gravity)
4265 {
4266   ClutterTransformInfo *info;
4267   GObject *obj;
4268
4269   info = _clutter_actor_get_transform_info (self);
4270   obj = G_OBJECT (self);
4271
4272   if (gravity == CLUTTER_GRAVITY_NONE)
4273     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4274   else
4275     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4276
4277   self->priv->transform_valid = FALSE;
4278
4279   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4280   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4281   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4282
4283   clutter_actor_queue_redraw (self);
4284 }
4285
4286 static inline void
4287 clutter_actor_set_anchor_coord (ClutterActor      *self,
4288                                 ClutterRotateAxis  axis,
4289                                 gfloat             coord)
4290 {
4291   GObject *obj = G_OBJECT (self);
4292   ClutterTransformInfo *info;
4293   gfloat anchor_x, anchor_y;
4294
4295   info = _clutter_actor_get_transform_info (self);
4296
4297   g_object_freeze_notify (obj);
4298
4299   clutter_anchor_coord_get_units (self, &info->anchor,
4300                                   &anchor_x,
4301                                   &anchor_y,
4302                                   NULL);
4303
4304   if (info->anchor.is_fractional)
4305     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4306
4307   switch (axis)
4308     {
4309     case CLUTTER_X_AXIS:
4310       clutter_anchor_coord_set_units (&info->anchor,
4311                                       coord,
4312                                       anchor_y,
4313                                       0.0);
4314       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4315       break;
4316
4317     case CLUTTER_Y_AXIS:
4318       clutter_anchor_coord_set_units (&info->anchor,
4319                                       anchor_x,
4320                                       coord,
4321                                       0.0);
4322       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4323       break;
4324
4325     default:
4326       g_assert_not_reached ();
4327     }
4328
4329   self->priv->transform_valid = FALSE;
4330
4331   clutter_actor_queue_redraw (self);
4332
4333   g_object_thaw_notify (obj);
4334 }
4335
4336 static void
4337 clutter_actor_set_property (GObject      *object,
4338                             guint         prop_id,
4339                             const GValue *value,
4340                             GParamSpec   *pspec)
4341 {
4342   ClutterActor *actor = CLUTTER_ACTOR (object);
4343   ClutterActorPrivate *priv = actor->priv;
4344
4345   switch (prop_id)
4346     {
4347     case PROP_X:
4348       clutter_actor_set_x (actor, g_value_get_float (value));
4349       break;
4350
4351     case PROP_Y:
4352       clutter_actor_set_y (actor, g_value_get_float (value));
4353       break;
4354
4355     case PROP_POSITION:
4356       {
4357         const ClutterPoint *pos = g_value_get_boxed (value);
4358
4359         if (pos != NULL)
4360           clutter_actor_set_position (actor, pos->x, pos->y);
4361         else
4362           clutter_actor_set_fixed_position_set (actor, FALSE);
4363       }
4364       break;
4365
4366     case PROP_WIDTH:
4367       clutter_actor_set_width (actor, g_value_get_float (value));
4368       break;
4369
4370     case PROP_HEIGHT:
4371       clutter_actor_set_height (actor, g_value_get_float (value));
4372       break;
4373
4374     case PROP_SIZE:
4375       {
4376         const ClutterSize *size = g_value_get_boxed (value);
4377
4378         if (size != NULL)
4379           clutter_actor_set_size (actor, size->width, size->height);
4380         else
4381           clutter_actor_set_size (actor, -1, -1);
4382       }
4383       break;
4384
4385     case PROP_FIXED_X:
4386       clutter_actor_set_x (actor, g_value_get_float (value));
4387       break;
4388
4389     case PROP_FIXED_Y:
4390       clutter_actor_set_y (actor, g_value_get_float (value));
4391       break;
4392
4393     case PROP_FIXED_POSITION_SET:
4394       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4395       break;
4396
4397     case PROP_MIN_WIDTH:
4398       clutter_actor_set_min_width (actor, g_value_get_float (value));
4399       break;
4400
4401     case PROP_MIN_HEIGHT:
4402       clutter_actor_set_min_height (actor, g_value_get_float (value));
4403       break;
4404
4405     case PROP_NATURAL_WIDTH:
4406       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4407       break;
4408
4409     case PROP_NATURAL_HEIGHT:
4410       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4411       break;
4412
4413     case PROP_MIN_WIDTH_SET:
4414       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4415       break;
4416
4417     case PROP_MIN_HEIGHT_SET:
4418       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4419       break;
4420
4421     case PROP_NATURAL_WIDTH_SET:
4422       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4423       break;
4424
4425     case PROP_NATURAL_HEIGHT_SET:
4426       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4427       break;
4428
4429     case PROP_REQUEST_MODE:
4430       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4431       break;
4432
4433     case PROP_DEPTH:
4434       clutter_actor_set_depth (actor, g_value_get_float (value));
4435       break;
4436
4437     case PROP_OPACITY:
4438       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4439       break;
4440
4441     case PROP_OFFSCREEN_REDIRECT:
4442       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4443       break;
4444
4445     case PROP_NAME:
4446       clutter_actor_set_name (actor, g_value_get_string (value));
4447       break;
4448
4449     case PROP_VISIBLE:
4450       if (g_value_get_boolean (value) == TRUE)
4451         clutter_actor_show (actor);
4452       else
4453         clutter_actor_hide (actor);
4454       break;
4455
4456     case PROP_SCALE_X:
4457       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4458                                       g_value_get_double (value));
4459       break;
4460
4461     case PROP_SCALE_Y:
4462       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4463                                       g_value_get_double (value));
4464       break;
4465
4466     case PROP_SCALE_CENTER_X:
4467       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4468                                       g_value_get_float (value));
4469       break;
4470
4471     case PROP_SCALE_CENTER_Y:
4472       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4473                                       g_value_get_float (value));
4474       break;
4475
4476     case PROP_SCALE_GRAVITY:
4477       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4478       break;
4479
4480     case PROP_CLIP:
4481       {
4482         const ClutterGeometry *geom = g_value_get_boxed (value);
4483
4484         clutter_actor_set_clip (actor,
4485                                 geom->x, geom->y,
4486                                 geom->width, geom->height);
4487       }
4488       break;
4489
4490     case PROP_CLIP_TO_ALLOCATION:
4491       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4492       break;
4493
4494     case PROP_REACTIVE:
4495       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4496       break;
4497
4498     case PROP_ROTATION_ANGLE_X:
4499       clutter_actor_set_rotation_angle (actor,
4500                                         CLUTTER_X_AXIS,
4501                                         g_value_get_double (value));
4502       break;
4503
4504     case PROP_ROTATION_ANGLE_Y:
4505       clutter_actor_set_rotation_angle (actor,
4506                                         CLUTTER_Y_AXIS,
4507                                         g_value_get_double (value));
4508       break;
4509
4510     case PROP_ROTATION_ANGLE_Z:
4511       clutter_actor_set_rotation_angle (actor,
4512                                         CLUTTER_Z_AXIS,
4513                                         g_value_get_double (value));
4514       break;
4515
4516     case PROP_ROTATION_CENTER_X:
4517       clutter_actor_set_rotation_center_internal (actor,
4518                                                   CLUTTER_X_AXIS,
4519                                                   g_value_get_boxed (value));
4520       break;
4521
4522     case PROP_ROTATION_CENTER_Y:
4523       clutter_actor_set_rotation_center_internal (actor,
4524                                                   CLUTTER_Y_AXIS,
4525                                                   g_value_get_boxed (value));
4526       break;
4527
4528     case PROP_ROTATION_CENTER_Z:
4529       clutter_actor_set_rotation_center_internal (actor,
4530                                                   CLUTTER_Z_AXIS,
4531                                                   g_value_get_boxed (value));
4532       break;
4533
4534     case PROP_ROTATION_CENTER_Z_GRAVITY:
4535       {
4536         const ClutterTransformInfo *info;
4537
4538         info = _clutter_actor_get_transform_info_or_defaults (actor);
4539         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4540                                                    g_value_get_enum (value));
4541       }
4542       break;
4543
4544     case PROP_ANCHOR_X:
4545       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4546                                       g_value_get_float (value));
4547       break;
4548
4549     case PROP_ANCHOR_Y:
4550       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4551                                       g_value_get_float (value));
4552       break;
4553
4554     case PROP_ANCHOR_GRAVITY:
4555       clutter_actor_set_anchor_point_from_gravity (actor,
4556                                                    g_value_get_enum (value));
4557       break;
4558
4559     case PROP_SHOW_ON_SET_PARENT:
4560       priv->show_on_set_parent = g_value_get_boolean (value);
4561       break;
4562
4563     case PROP_TEXT_DIRECTION:
4564       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4565       break;
4566
4567     case PROP_ACTIONS:
4568       clutter_actor_add_action (actor, g_value_get_object (value));
4569       break;
4570
4571     case PROP_CONSTRAINTS:
4572       clutter_actor_add_constraint (actor, g_value_get_object (value));
4573       break;
4574
4575     case PROP_EFFECT:
4576       clutter_actor_add_effect (actor, g_value_get_object (value));
4577       break;
4578
4579     case PROP_LAYOUT_MANAGER:
4580       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4581       break;
4582
4583     case PROP_X_ALIGN:
4584       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4585       break;
4586
4587     case PROP_Y_ALIGN:
4588       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4589       break;
4590
4591     case PROP_MARGIN_TOP:
4592       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4593       break;
4594
4595     case PROP_MARGIN_BOTTOM:
4596       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4597       break;
4598
4599     case PROP_MARGIN_LEFT:
4600       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4601       break;
4602
4603     case PROP_MARGIN_RIGHT:
4604       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4605       break;
4606
4607     case PROP_BACKGROUND_COLOR:
4608       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4609       break;
4610
4611     case PROP_CONTENT:
4612       clutter_actor_set_content (actor, g_value_get_object (value));
4613       break;
4614
4615     case PROP_CONTENT_GRAVITY:
4616       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4617       break;
4618
4619     case PROP_MINIFICATION_FILTER:
4620       clutter_actor_set_content_scaling_filters (actor,
4621                                                  g_value_get_enum (value),
4622                                                  actor->priv->mag_filter);
4623       break;
4624
4625     case PROP_MAGNIFICATION_FILTER:
4626       clutter_actor_set_content_scaling_filters (actor,
4627                                                  actor->priv->min_filter,
4628                                                  g_value_get_enum (value));
4629       break;
4630
4631     default:
4632       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4633       break;
4634     }
4635 }
4636
4637 static void
4638 clutter_actor_get_property (GObject    *object,
4639                             guint       prop_id,
4640                             GValue     *value,
4641                             GParamSpec *pspec)
4642 {
4643   ClutterActor *actor = CLUTTER_ACTOR (object);
4644   ClutterActorPrivate *priv = actor->priv;
4645
4646   switch (prop_id)
4647     {
4648     case PROP_X:
4649       g_value_set_float (value, clutter_actor_get_x (actor));
4650       break;
4651
4652     case PROP_Y:
4653       g_value_set_float (value, clutter_actor_get_y (actor));
4654       break;
4655
4656     case PROP_POSITION:
4657       {
4658         ClutterPoint position;
4659
4660         clutter_point_init (&position,
4661                             clutter_actor_get_x (actor),
4662                             clutter_actor_get_y (actor));
4663         g_value_set_boxed (value, &position);
4664       }
4665       break;
4666
4667     case PROP_WIDTH:
4668       g_value_set_float (value, clutter_actor_get_width (actor));
4669       break;
4670
4671     case PROP_HEIGHT:
4672       g_value_set_float (value, clutter_actor_get_height (actor));
4673       break;
4674
4675     case PROP_SIZE:
4676       {
4677         ClutterSize size;
4678
4679         clutter_size_init (&size,
4680                            clutter_actor_get_width (actor),
4681                            clutter_actor_get_height (actor));
4682         g_value_set_boxed (value, &size);
4683       }
4684       break;
4685
4686     case PROP_FIXED_X:
4687       {
4688         const ClutterLayoutInfo *info;
4689
4690         info = _clutter_actor_get_layout_info_or_defaults (actor);
4691         g_value_set_float (value, info->fixed_pos.x);
4692       }
4693       break;
4694
4695     case PROP_FIXED_Y:
4696       {
4697         const ClutterLayoutInfo *info;
4698
4699         info = _clutter_actor_get_layout_info_or_defaults (actor);
4700         g_value_set_float (value, info->fixed_pos.y);
4701       }
4702       break;
4703
4704     case PROP_FIXED_POSITION_SET:
4705       g_value_set_boolean (value, priv->position_set);
4706       break;
4707
4708     case PROP_MIN_WIDTH:
4709       {
4710         const ClutterLayoutInfo *info;
4711
4712         info = _clutter_actor_get_layout_info_or_defaults (actor);
4713         g_value_set_float (value, info->minimum.width);
4714       }
4715       break;
4716
4717     case PROP_MIN_HEIGHT:
4718       {
4719         const ClutterLayoutInfo *info;
4720
4721         info = _clutter_actor_get_layout_info_or_defaults (actor);
4722         g_value_set_float (value, info->minimum.height);
4723       }
4724       break;
4725
4726     case PROP_NATURAL_WIDTH:
4727       {
4728         const ClutterLayoutInfo *info;
4729
4730         info = _clutter_actor_get_layout_info_or_defaults (actor);
4731         g_value_set_float (value, info->natural.width);
4732       }
4733       break;
4734
4735     case PROP_NATURAL_HEIGHT:
4736       {
4737         const ClutterLayoutInfo *info;
4738
4739         info = _clutter_actor_get_layout_info_or_defaults (actor);
4740         g_value_set_float (value, info->natural.height);
4741       }
4742       break;
4743
4744     case PROP_MIN_WIDTH_SET:
4745       g_value_set_boolean (value, priv->min_width_set);
4746       break;
4747
4748     case PROP_MIN_HEIGHT_SET:
4749       g_value_set_boolean (value, priv->min_height_set);
4750       break;
4751
4752     case PROP_NATURAL_WIDTH_SET:
4753       g_value_set_boolean (value, priv->natural_width_set);
4754       break;
4755
4756     case PROP_NATURAL_HEIGHT_SET:
4757       g_value_set_boolean (value, priv->natural_height_set);
4758       break;
4759
4760     case PROP_REQUEST_MODE:
4761       g_value_set_enum (value, priv->request_mode);
4762       break;
4763
4764     case PROP_ALLOCATION:
4765       g_value_set_boxed (value, &priv->allocation);
4766       break;
4767
4768     case PROP_DEPTH:
4769       g_value_set_float (value, clutter_actor_get_depth (actor));
4770       break;
4771
4772     case PROP_OPACITY:
4773       g_value_set_uint (value, priv->opacity);
4774       break;
4775
4776     case PROP_OFFSCREEN_REDIRECT:
4777       g_value_set_enum (value, priv->offscreen_redirect);
4778       break;
4779
4780     case PROP_NAME:
4781       g_value_set_string (value, priv->name);
4782       break;
4783
4784     case PROP_VISIBLE:
4785       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4786       break;
4787
4788     case PROP_MAPPED:
4789       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4790       break;
4791
4792     case PROP_REALIZED:
4793       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4794       break;
4795
4796     case PROP_HAS_CLIP:
4797       g_value_set_boolean (value, priv->has_clip);
4798       break;
4799
4800     case PROP_CLIP:
4801       {
4802         ClutterGeometry clip;
4803
4804         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4805         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4806         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4807         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4808
4809         g_value_set_boxed (value, &clip);
4810       }
4811       break;
4812
4813     case PROP_CLIP_TO_ALLOCATION:
4814       g_value_set_boolean (value, priv->clip_to_allocation);
4815       break;
4816
4817     case PROP_SCALE_X:
4818       {
4819         const ClutterTransformInfo *info;
4820
4821         info = _clutter_actor_get_transform_info_or_defaults (actor);
4822         g_value_set_double (value, info->scale_x);
4823       }
4824       break;
4825
4826     case PROP_SCALE_Y:
4827       {
4828         const ClutterTransformInfo *info;
4829
4830         info = _clutter_actor_get_transform_info_or_defaults (actor);
4831         g_value_set_double (value, info->scale_y);
4832       }
4833       break;
4834
4835     case PROP_SCALE_CENTER_X:
4836       {
4837         gfloat center;
4838
4839         clutter_actor_get_scale_center (actor, &center, NULL);
4840
4841         g_value_set_float (value, center);
4842       }
4843       break;
4844
4845     case PROP_SCALE_CENTER_Y:
4846       {
4847         gfloat center;
4848
4849         clutter_actor_get_scale_center (actor, NULL, &center);
4850
4851         g_value_set_float (value, center);
4852       }
4853       break;
4854
4855     case PROP_SCALE_GRAVITY:
4856       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4857       break;
4858
4859     case PROP_REACTIVE:
4860       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4861       break;
4862
4863     case PROP_ROTATION_ANGLE_X:
4864       {
4865         const ClutterTransformInfo *info;
4866
4867         info = _clutter_actor_get_transform_info_or_defaults (actor);
4868         g_value_set_double (value, info->rx_angle);
4869       }
4870       break;
4871
4872     case PROP_ROTATION_ANGLE_Y:
4873       {
4874         const ClutterTransformInfo *info;
4875
4876         info = _clutter_actor_get_transform_info_or_defaults (actor);
4877         g_value_set_double (value, info->ry_angle);
4878       }
4879       break;
4880
4881     case PROP_ROTATION_ANGLE_Z:
4882       {
4883         const ClutterTransformInfo *info;
4884
4885         info = _clutter_actor_get_transform_info_or_defaults (actor);
4886         g_value_set_double (value, info->rz_angle);
4887       }
4888       break;
4889
4890     case PROP_ROTATION_CENTER_X:
4891       {
4892         ClutterVertex center;
4893
4894         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4895                                     &center.x,
4896                                     &center.y,
4897                                     &center.z);
4898
4899         g_value_set_boxed (value, &center);
4900       }
4901       break;
4902
4903     case PROP_ROTATION_CENTER_Y:
4904       {
4905         ClutterVertex center;
4906
4907         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4908                                     &center.x,
4909                                     &center.y,
4910                                     &center.z);
4911
4912         g_value_set_boxed (value, &center);
4913       }
4914       break;
4915
4916     case PROP_ROTATION_CENTER_Z:
4917       {
4918         ClutterVertex center;
4919
4920         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4921                                     &center.x,
4922                                     &center.y,
4923                                     &center.z);
4924
4925         g_value_set_boxed (value, &center);
4926       }
4927       break;
4928
4929     case PROP_ROTATION_CENTER_Z_GRAVITY:
4930       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4931       break;
4932
4933     case PROP_ANCHOR_X:
4934       {
4935         const ClutterTransformInfo *info;
4936         gfloat anchor_x;
4937
4938         info = _clutter_actor_get_transform_info_or_defaults (actor);
4939         clutter_anchor_coord_get_units (actor, &info->anchor,
4940                                         &anchor_x,
4941                                         NULL,
4942                                         NULL);
4943         g_value_set_float (value, anchor_x);
4944       }
4945       break;
4946
4947     case PROP_ANCHOR_Y:
4948       {
4949         const ClutterTransformInfo *info;
4950         gfloat anchor_y;
4951
4952         info = _clutter_actor_get_transform_info_or_defaults (actor);
4953         clutter_anchor_coord_get_units (actor, &info->anchor,
4954                                         NULL,
4955                                         &anchor_y,
4956                                         NULL);
4957         g_value_set_float (value, anchor_y);
4958       }
4959       break;
4960
4961     case PROP_ANCHOR_GRAVITY:
4962       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4963       break;
4964
4965     case PROP_SHOW_ON_SET_PARENT:
4966       g_value_set_boolean (value, priv->show_on_set_parent);
4967       break;
4968
4969     case PROP_TEXT_DIRECTION:
4970       g_value_set_enum (value, priv->text_direction);
4971       break;
4972
4973     case PROP_HAS_POINTER:
4974       g_value_set_boolean (value, priv->has_pointer);
4975       break;
4976
4977     case PROP_LAYOUT_MANAGER:
4978       g_value_set_object (value, priv->layout_manager);
4979       break;
4980
4981     case PROP_X_ALIGN:
4982       {
4983         const ClutterLayoutInfo *info;
4984
4985         info = _clutter_actor_get_layout_info_or_defaults (actor);
4986         g_value_set_enum (value, info->x_align);
4987       }
4988       break;
4989
4990     case PROP_Y_ALIGN:
4991       {
4992         const ClutterLayoutInfo *info;
4993
4994         info = _clutter_actor_get_layout_info_or_defaults (actor);
4995         g_value_set_enum (value, info->y_align);
4996       }
4997       break;
4998
4999     case PROP_MARGIN_TOP:
5000       {
5001         const ClutterLayoutInfo *info;
5002
5003         info = _clutter_actor_get_layout_info_or_defaults (actor);
5004         g_value_set_float (value, info->margin.top);
5005       }
5006       break;
5007
5008     case PROP_MARGIN_BOTTOM:
5009       {
5010         const ClutterLayoutInfo *info;
5011
5012         info = _clutter_actor_get_layout_info_or_defaults (actor);
5013         g_value_set_float (value, info->margin.bottom);
5014       }
5015       break;
5016
5017     case PROP_MARGIN_LEFT:
5018       {
5019         const ClutterLayoutInfo *info;
5020
5021         info = _clutter_actor_get_layout_info_or_defaults (actor);
5022         g_value_set_float (value, info->margin.left);
5023       }
5024       break;
5025
5026     case PROP_MARGIN_RIGHT:
5027       {
5028         const ClutterLayoutInfo *info;
5029
5030         info = _clutter_actor_get_layout_info_or_defaults (actor);
5031         g_value_set_float (value, info->margin.right);
5032       }
5033       break;
5034
5035     case PROP_BACKGROUND_COLOR_SET:
5036       g_value_set_boolean (value, priv->bg_color_set);
5037       break;
5038
5039     case PROP_BACKGROUND_COLOR:
5040       g_value_set_boxed (value, &priv->bg_color);
5041       break;
5042
5043     case PROP_FIRST_CHILD:
5044       g_value_set_object (value, priv->first_child);
5045       break;
5046
5047     case PROP_LAST_CHILD:
5048       g_value_set_object (value, priv->last_child);
5049       break;
5050
5051     case PROP_CONTENT:
5052       g_value_set_object (value, priv->content);
5053       break;
5054
5055     case PROP_CONTENT_GRAVITY:
5056       g_value_set_enum (value, priv->content_gravity);
5057       break;
5058
5059     case PROP_CONTENT_BOX:
5060       {
5061         ClutterActorBox box = { 0, };
5062
5063         clutter_actor_get_content_box (actor, &box);
5064         g_value_set_boxed (value, &box);
5065       }
5066       break;
5067
5068     case PROP_MINIFICATION_FILTER:
5069       g_value_set_enum (value, priv->min_filter);
5070       break;
5071
5072     case PROP_MAGNIFICATION_FILTER:
5073       g_value_set_enum (value, priv->mag_filter);
5074       break;
5075
5076     default:
5077       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5078       break;
5079     }
5080 }
5081
5082 static void
5083 clutter_actor_dispose (GObject *object)
5084 {
5085   ClutterActor *self = CLUTTER_ACTOR (object);
5086   ClutterActorPrivate *priv = self->priv;
5087
5088   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5089                 priv->id,
5090                 g_type_name (G_OBJECT_TYPE (self)),
5091                 object->ref_count);
5092
5093   g_signal_emit (self, actor_signals[DESTROY], 0);
5094
5095   /* avoid recursing when called from clutter_actor_destroy() */
5096   if (priv->parent != NULL)
5097     {
5098       ClutterActor *parent = priv->parent;
5099
5100       /* go through the Container implementation unless this
5101        * is an internal child and has been marked as such.
5102        *
5103        * removing the actor from its parent will reset the
5104        * realized and mapped states.
5105        */
5106       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5107         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5108       else
5109         clutter_actor_remove_child_internal (parent, self,
5110                                              REMOVE_CHILD_LEGACY_FLAGS);
5111     }
5112
5113   /* parent must be gone at this point */
5114   g_assert (priv->parent == NULL);
5115
5116   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5117     {
5118       /* can't be mapped or realized with no parent */
5119       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5120       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5121     }
5122
5123   g_clear_object (&priv->pango_context);
5124   g_clear_object (&priv->actions);
5125   g_clear_object (&priv->constraints);
5126   g_clear_object (&priv->effects);
5127   g_clear_object (&priv->flatten_effect);
5128
5129   if (priv->layout_manager != NULL)
5130     {
5131       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5132       g_clear_object (&priv->layout_manager);
5133     }
5134
5135   if (priv->content != NULL)
5136     {
5137       _clutter_content_detached (priv->content, self);
5138       g_clear_object (&priv->content);
5139     }
5140
5141   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5142 }
5143
5144 static void
5145 clutter_actor_finalize (GObject *object)
5146 {
5147   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5148
5149   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5150                 priv->name != NULL ? priv->name : "<none>",
5151                 priv->id,
5152                 g_type_name (G_OBJECT_TYPE (object)));
5153
5154   _clutter_context_release_id (priv->id);
5155
5156   g_free (priv->name);
5157
5158   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5159 }
5160
5161
5162 /**
5163  * clutter_actor_get_accessible:
5164  * @self: a #ClutterActor
5165  *
5166  * Returns the accessible object that describes the actor to an
5167  * assistive technology.
5168  *
5169  * If no class-specific #AtkObject implementation is available for the
5170  * actor instance in question, it will inherit an #AtkObject
5171  * implementation from the first ancestor class for which such an
5172  * implementation is defined.
5173  *
5174  * The documentation of the <ulink
5175  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5176  * library contains more information about accessible objects and
5177  * their uses.
5178  *
5179  * Returns: (transfer none): the #AtkObject associated with @actor
5180  */
5181 AtkObject *
5182 clutter_actor_get_accessible (ClutterActor *self)
5183 {
5184   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5185
5186   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5187 }
5188
5189 static AtkObject *
5190 clutter_actor_real_get_accessible (ClutterActor *actor)
5191 {
5192   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5193 }
5194
5195 static AtkObject *
5196 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5197 {
5198   AtkObject *accessible;
5199
5200   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5201   if (accessible != NULL)
5202     g_object_ref (accessible);
5203
5204   return accessible;
5205 }
5206
5207 static void
5208 atk_implementor_iface_init (AtkImplementorIface *iface)
5209 {
5210   iface->ref_accessible = _clutter_actor_ref_accessible;
5211 }
5212
5213 static gboolean
5214 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5215                                            ClutterPaintVolume *volume)
5216 {
5217   ClutterActorPrivate *priv = self->priv;
5218   gboolean res = TRUE;
5219
5220   /* we start from the allocation */
5221   clutter_paint_volume_set_width (volume,
5222                                   priv->allocation.x2 - priv->allocation.x1);
5223   clutter_paint_volume_set_height (volume,
5224                                    priv->allocation.y2 - priv->allocation.y1);
5225
5226   /* if the actor has a clip set then we have a pretty definite
5227    * size for the paint volume: the actor cannot possibly paint
5228    * outside the clip region.
5229    */
5230   if (priv->clip_to_allocation)
5231     {
5232       /* the allocation has already been set, so we just flip the
5233        * return value
5234        */
5235       res = TRUE;
5236     }
5237   else
5238     {
5239       ClutterActor *child;
5240
5241       if (priv->has_clip &&
5242           priv->clip.width >= 0 &&
5243           priv->clip.height >= 0)
5244         {
5245           ClutterVertex origin;
5246
5247           origin.x = priv->clip.x;
5248           origin.y = priv->clip.y;
5249           origin.z = 0;
5250
5251           clutter_paint_volume_set_origin (volume, &origin);
5252           clutter_paint_volume_set_width (volume, priv->clip.width);
5253           clutter_paint_volume_set_height (volume, priv->clip.height);
5254
5255           res = TRUE;
5256         }
5257
5258       /* if we don't have children we just bail out here... */
5259       if (priv->n_children == 0)
5260         return res;
5261
5262       /* ...but if we have children then we ask for their paint volume in
5263        * our coordinates. if any of our children replies that it doesn't
5264        * have a paint volume, we bail out
5265        */
5266       for (child = priv->first_child;
5267            child != NULL;
5268            child = child->priv->next_sibling)
5269         {
5270           const ClutterPaintVolume *child_volume;
5271
5272           if (!CLUTTER_ACTOR_IS_MAPPED (child))
5273             continue;
5274
5275           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5276           if (child_volume == NULL)
5277             {
5278               res = FALSE;
5279               break;
5280             }
5281
5282           clutter_paint_volume_union (volume, child_volume);
5283           res = TRUE;
5284         }
5285     }
5286
5287   return res;
5288
5289 }
5290
5291 static gboolean
5292 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5293                                      ClutterPaintVolume *volume)
5294 {
5295   ClutterActorClass *klass;
5296   gboolean res;
5297
5298   klass = CLUTTER_ACTOR_GET_CLASS (self);
5299
5300   /* XXX - this thoroughly sucks, but we don't want to penalize users
5301    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5302    * redraw. This should go away in 2.0.
5303    */
5304   if (klass->paint == clutter_actor_real_paint &&
5305       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5306     {
5307       res = TRUE;
5308     }
5309   else
5310     {
5311       /* this is the default return value: we cannot know if a class
5312        * is going to paint outside its allocation, so we take the
5313        * conservative approach.
5314        */
5315       res = FALSE;
5316     }
5317
5318   /* update_default_paint_volume() should only fail if one of the children
5319    * reported an invalid, or no, paint volume
5320    */
5321   if (!clutter_actor_update_default_paint_volume (self, volume))
5322     return FALSE;
5323
5324   return res;
5325 }
5326
5327 /**
5328  * clutter_actor_get_default_paint_volume:
5329  * @self: a #ClutterActor
5330  *
5331  * Retrieves the default paint volume for @self.
5332  *
5333  * This function provides the same #ClutterPaintVolume that would be
5334  * computed by the default implementation inside #ClutterActor of the
5335  * #ClutterActorClass.get_paint_volume() virtual function.
5336  *
5337  * This function should only be used by #ClutterActor subclasses that
5338  * cannot chain up to the parent implementation when computing their
5339  * paint volume.
5340  *
5341  * Return value: (transfer none): a pointer to the default
5342  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5343  *   the actor could not compute a valid paint volume. The returned value
5344  *   is not guaranteed to be stable across multiple frames, so if you
5345  *   want to retain it, you will need to copy it using
5346  *   clutter_paint_volume_copy().
5347  *
5348  * Since: 1.10
5349  */
5350 const ClutterPaintVolume *
5351 clutter_actor_get_default_paint_volume (ClutterActor *self)
5352 {
5353   ClutterPaintVolume volume;
5354   ClutterPaintVolume *res;
5355
5356   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5357
5358   res = NULL;
5359   _clutter_paint_volume_init_static (&volume, self);
5360   if (clutter_actor_update_default_paint_volume (self, &volume))
5361     {
5362       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5363
5364       if (stage != NULL)
5365         {
5366           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5367           _clutter_paint_volume_copy_static (&volume, res);
5368         }
5369     }
5370
5371   clutter_paint_volume_free (&volume);
5372
5373   return res;
5374 }
5375
5376 static gboolean
5377 clutter_actor_real_has_overlaps (ClutterActor *self)
5378 {
5379   /* By default we'll assume that all actors need an offscreen redirect to get
5380    * the correct opacity. Actors such as ClutterTexture that would never need
5381    * an offscreen redirect can override this to return FALSE. */
5382   return TRUE;
5383 }
5384
5385 static void
5386 clutter_actor_real_destroy (ClutterActor *actor)
5387 {
5388   ClutterActorIter iter;
5389
5390   g_object_freeze_notify (G_OBJECT (actor));
5391
5392   clutter_actor_iter_init (&iter, actor);
5393   while (clutter_actor_iter_next (&iter, NULL))
5394     clutter_actor_iter_destroy (&iter);
5395
5396   g_object_thaw_notify (G_OBJECT (actor));
5397 }
5398
5399 static GObject *
5400 clutter_actor_constructor (GType gtype,
5401                            guint n_props,
5402                            GObjectConstructParam *props)
5403 {
5404   GObjectClass *gobject_class;
5405   ClutterActor *self;
5406   GObject *retval;
5407
5408   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5409   retval = gobject_class->constructor (gtype, n_props, props);
5410   self = CLUTTER_ACTOR (retval);
5411
5412   if (self->priv->layout_manager == NULL)
5413     {
5414       ClutterLayoutManager *default_layout;
5415
5416       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5417
5418       default_layout = clutter_fixed_layout_new ();
5419       clutter_actor_set_layout_manager (self, default_layout);
5420     }
5421
5422   return retval;
5423 }
5424
5425 static void
5426 clutter_actor_class_init (ClutterActorClass *klass)
5427 {
5428   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5429
5430   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5431   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5432   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5433   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5434
5435   object_class->constructor = clutter_actor_constructor;
5436   object_class->set_property = clutter_actor_set_property;
5437   object_class->get_property = clutter_actor_get_property;
5438   object_class->dispose = clutter_actor_dispose;
5439   object_class->finalize = clutter_actor_finalize;
5440
5441   klass->show = clutter_actor_real_show;
5442   klass->show_all = clutter_actor_show;
5443   klass->hide = clutter_actor_real_hide;
5444   klass->hide_all = clutter_actor_hide;
5445   klass->map = clutter_actor_real_map;
5446   klass->unmap = clutter_actor_real_unmap;
5447   klass->unrealize = clutter_actor_real_unrealize;
5448   klass->pick = clutter_actor_real_pick;
5449   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5450   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5451   klass->allocate = clutter_actor_real_allocate;
5452   klass->queue_redraw = clutter_actor_real_queue_redraw;
5453   klass->queue_relayout = clutter_actor_real_queue_relayout;
5454   klass->apply_transform = clutter_actor_real_apply_transform;
5455   klass->get_accessible = clutter_actor_real_get_accessible;
5456   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5457   klass->has_overlaps = clutter_actor_real_has_overlaps;
5458   klass->paint = clutter_actor_real_paint;
5459   klass->destroy = clutter_actor_real_destroy;
5460
5461   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5462
5463   /**
5464    * ClutterActor:x:
5465    *
5466    * X coordinate of the actor in pixels. If written, forces a fixed
5467    * position for the actor. If read, returns the fixed position if any,
5468    * otherwise the allocation if available, otherwise 0.
5469    *
5470    * The #ClutterActor:x property is animatable.
5471    */
5472   obj_props[PROP_X] =
5473     g_param_spec_float ("x",
5474                         P_("X coordinate"),
5475                         P_("X coordinate of the actor"),
5476                         -G_MAXFLOAT, G_MAXFLOAT,
5477                         0.0,
5478                         G_PARAM_READWRITE |
5479                         G_PARAM_STATIC_STRINGS |
5480                         CLUTTER_PARAM_ANIMATABLE);
5481
5482   /**
5483    * ClutterActor:y:
5484    *
5485    * Y coordinate of the actor in pixels. If written, forces a fixed
5486    * position for the actor.  If read, returns the fixed position if
5487    * any, otherwise the allocation if available, otherwise 0.
5488    *
5489    * The #ClutterActor:y property is animatable.
5490    */
5491   obj_props[PROP_Y] =
5492     g_param_spec_float ("y",
5493                         P_("Y coordinate"),
5494                         P_("Y coordinate of the actor"),
5495                         -G_MAXFLOAT, G_MAXFLOAT,
5496                         0.0,
5497                         G_PARAM_READWRITE |
5498                         G_PARAM_STATIC_STRINGS |
5499                         CLUTTER_PARAM_ANIMATABLE);
5500
5501   /**
5502    * ClutterActor:position:
5503    *
5504    * The position of the origin of the actor.
5505    *
5506    * This property is a shorthand for setting and getting the
5507    * #ClutterActor:x and #ClutterActor:y properties at the same
5508    * time.
5509    *
5510    * The #ClutterActor:position property is animatable.
5511    *
5512    * Since: 1.12
5513    */
5514   obj_props[PROP_POSITION] =
5515     g_param_spec_boxed ("position",
5516                         P_("Position"),
5517                         P_("The position of the origin of the actor"),
5518                         CLUTTER_TYPE_POINT,
5519                         G_PARAM_READWRITE |
5520                         G_PARAM_STATIC_STRINGS |
5521                         CLUTTER_PARAM_ANIMATABLE);
5522
5523   /**
5524    * ClutterActor:width:
5525    *
5526    * Width of the actor (in pixels). If written, forces the minimum and
5527    * natural size request of the actor to the given width. If read, returns
5528    * the allocated width if available, otherwise the width request.
5529    *
5530    * The #ClutterActor:width property is animatable.
5531    */
5532   obj_props[PROP_WIDTH] =
5533     g_param_spec_float ("width",
5534                         P_("Width"),
5535                         P_("Width of the actor"),
5536                         0.0, G_MAXFLOAT,
5537                         0.0,
5538                         G_PARAM_READWRITE |
5539                         G_PARAM_STATIC_STRINGS |
5540                         CLUTTER_PARAM_ANIMATABLE);
5541
5542   /**
5543    * ClutterActor:height:
5544    *
5545    * Height of the actor (in pixels).  If written, forces the minimum and
5546    * natural size request of the actor to the given height. If read, returns
5547    * the allocated height if available, otherwise the height request.
5548    *
5549    * The #ClutterActor:height property is animatable.
5550    */
5551   obj_props[PROP_HEIGHT] =
5552     g_param_spec_float ("height",
5553                         P_("Height"),
5554                         P_("Height of the actor"),
5555                         0.0, G_MAXFLOAT,
5556                         0.0,
5557                         G_PARAM_READWRITE |
5558                         G_PARAM_STATIC_STRINGS |
5559                         CLUTTER_PARAM_ANIMATABLE);
5560
5561   /**
5562    * ClutterActor:size:
5563    *
5564    * The size of the actor.
5565    *
5566    * This property is a shorthand for setting and getting the
5567    * #ClutterActor:width and #ClutterActor:height at the same time.
5568    *
5569    * The #ClutterActor:size property is animatable.
5570    *
5571    * Since: 1.12
5572    */
5573   obj_props[PROP_SIZE] =
5574     g_param_spec_boxed ("size",
5575                         P_("Size"),
5576                         P_("The size of the actor"),
5577                         CLUTTER_TYPE_SIZE,
5578                         G_PARAM_READWRITE |
5579                         G_PARAM_STATIC_STRINGS |
5580                         CLUTTER_PARAM_ANIMATABLE);
5581
5582   /**
5583    * ClutterActor:fixed-x:
5584    *
5585    * The fixed X position of the actor in pixels.
5586    *
5587    * Writing this property sets #ClutterActor:fixed-position-set
5588    * property as well, as a side effect
5589    *
5590    * Since: 0.8
5591    */
5592   obj_props[PROP_FIXED_X] =
5593     g_param_spec_float ("fixed-x",
5594                         P_("Fixed X"),
5595                         P_("Forced X position of the actor"),
5596                         -G_MAXFLOAT, G_MAXFLOAT,
5597                         0.0,
5598                         CLUTTER_PARAM_READWRITE);
5599
5600   /**
5601    * ClutterActor:fixed-y:
5602    *
5603    * The fixed Y position of the actor in pixels.
5604    *
5605    * Writing this property sets the #ClutterActor:fixed-position-set
5606    * property as well, as a side effect
5607    *
5608    * Since: 0.8
5609    */
5610   obj_props[PROP_FIXED_Y] =
5611     g_param_spec_float ("fixed-y",
5612                         P_("Fixed Y"),
5613                         P_("Forced Y position of the actor"),
5614                         -G_MAXFLOAT, G_MAXFLOAT,
5615                         0,
5616                         CLUTTER_PARAM_READWRITE);
5617
5618   /**
5619    * ClutterActor:fixed-position-set:
5620    *
5621    * This flag controls whether the #ClutterActor:fixed-x and
5622    * #ClutterActor:fixed-y properties are used
5623    *
5624    * Since: 0.8
5625    */
5626   obj_props[PROP_FIXED_POSITION_SET] =
5627     g_param_spec_boolean ("fixed-position-set",
5628                           P_("Fixed position set"),
5629                           P_("Whether to use fixed positioning for the actor"),
5630                           FALSE,
5631                           CLUTTER_PARAM_READWRITE);
5632
5633   /**
5634    * ClutterActor:min-width:
5635    *
5636    * A forced minimum width request for the actor, in pixels
5637    *
5638    * Writing this property sets the #ClutterActor:min-width-set property
5639    * as well, as a side effect.
5640    *
5641    *This property overrides the usual width request of the actor.
5642    *
5643    * Since: 0.8
5644    */
5645   obj_props[PROP_MIN_WIDTH] =
5646     g_param_spec_float ("min-width",
5647                         P_("Min Width"),
5648                         P_("Forced minimum width request for the actor"),
5649                         0.0, G_MAXFLOAT,
5650                         0.0,
5651                         CLUTTER_PARAM_READWRITE);
5652
5653   /**
5654    * ClutterActor:min-height:
5655    *
5656    * A forced minimum height request for the actor, in pixels
5657    *
5658    * Writing this property sets the #ClutterActor:min-height-set property
5659    * as well, as a side effect. This property overrides the usual height
5660    * request of the actor.
5661    *
5662    * Since: 0.8
5663    */
5664   obj_props[PROP_MIN_HEIGHT] =
5665     g_param_spec_float ("min-height",
5666                         P_("Min Height"),
5667                         P_("Forced minimum height request for the actor"),
5668                         0.0, G_MAXFLOAT,
5669                         0.0,
5670                         CLUTTER_PARAM_READWRITE);
5671
5672   /**
5673    * ClutterActor:natural-width:
5674    *
5675    * A forced natural width request for the actor, in pixels
5676    *
5677    * Writing this property sets the #ClutterActor:natural-width-set
5678    * property as well, as a side effect. This property overrides the
5679    * usual width request of the actor
5680    *
5681    * Since: 0.8
5682    */
5683   obj_props[PROP_NATURAL_WIDTH] =
5684     g_param_spec_float ("natural-width",
5685                         P_("Natural Width"),
5686                         P_("Forced natural width request for the actor"),
5687                         0.0, G_MAXFLOAT,
5688                         0.0,
5689                         CLUTTER_PARAM_READWRITE);
5690
5691   /**
5692    * ClutterActor:natural-height:
5693    *
5694    * A forced natural height request for the actor, in pixels
5695    *
5696    * Writing this property sets the #ClutterActor:natural-height-set
5697    * property as well, as a side effect. This property overrides the
5698    * usual height request of the actor
5699    *
5700    * Since: 0.8
5701    */
5702   obj_props[PROP_NATURAL_HEIGHT] =
5703     g_param_spec_float ("natural-height",
5704                         P_("Natural Height"),
5705                         P_("Forced natural height request for the actor"),
5706                         0.0, G_MAXFLOAT,
5707                         0.0,
5708                         CLUTTER_PARAM_READWRITE);
5709
5710   /**
5711    * ClutterActor:min-width-set:
5712    *
5713    * This flag controls whether the #ClutterActor:min-width property
5714    * is used
5715    *
5716    * Since: 0.8
5717    */
5718   obj_props[PROP_MIN_WIDTH_SET] =
5719     g_param_spec_boolean ("min-width-set",
5720                           P_("Minimum width set"),
5721                           P_("Whether to use the min-width property"),
5722                           FALSE,
5723                           CLUTTER_PARAM_READWRITE);
5724
5725   /**
5726    * ClutterActor:min-height-set:
5727    *
5728    * This flag controls whether the #ClutterActor:min-height property
5729    * is used
5730    *
5731    * Since: 0.8
5732    */
5733   obj_props[PROP_MIN_HEIGHT_SET] =
5734     g_param_spec_boolean ("min-height-set",
5735                           P_("Minimum height set"),
5736                           P_("Whether to use the min-height property"),
5737                           FALSE,
5738                           CLUTTER_PARAM_READWRITE);
5739
5740   /**
5741    * ClutterActor:natural-width-set:
5742    *
5743    * This flag controls whether the #ClutterActor:natural-width property
5744    * is used
5745    *
5746    * Since: 0.8
5747    */
5748   obj_props[PROP_NATURAL_WIDTH_SET] =
5749     g_param_spec_boolean ("natural-width-set",
5750                           P_("Natural width set"),
5751                           P_("Whether to use the natural-width property"),
5752                           FALSE,
5753                           CLUTTER_PARAM_READWRITE);
5754
5755   /**
5756    * ClutterActor:natural-height-set:
5757    *
5758    * This flag controls whether the #ClutterActor:natural-height property
5759    * is used
5760    *
5761    * Since: 0.8
5762    */
5763   obj_props[PROP_NATURAL_HEIGHT_SET] =
5764     g_param_spec_boolean ("natural-height-set",
5765                           P_("Natural height set"),
5766                           P_("Whether to use the natural-height property"),
5767                           FALSE,
5768                           CLUTTER_PARAM_READWRITE);
5769
5770   /**
5771    * ClutterActor:allocation:
5772    *
5773    * The allocation for the actor, in pixels
5774    *
5775    * This is property is read-only, but you might monitor it to know when an
5776    * actor moves or resizes
5777    *
5778    * Since: 0.8
5779    */
5780   obj_props[PROP_ALLOCATION] =
5781     g_param_spec_boxed ("allocation",
5782                         P_("Allocation"),
5783                         P_("The actor's allocation"),
5784                         CLUTTER_TYPE_ACTOR_BOX,
5785                         CLUTTER_PARAM_READABLE);
5786
5787   /**
5788    * ClutterActor:request-mode:
5789    *
5790    * Request mode for the #ClutterActor. The request mode determines the
5791    * type of geometry management used by the actor, either height for width
5792    * (the default) or width for height.
5793    *
5794    * For actors implementing height for width, the parent container should get
5795    * the preferred width first, and then the preferred height for that width.
5796    *
5797    * For actors implementing width for height, the parent container should get
5798    * the preferred height first, and then the preferred width for that height.
5799    *
5800    * For instance:
5801    *
5802    * |[
5803    *   ClutterRequestMode mode;
5804    *   gfloat natural_width, min_width;
5805    *   gfloat natural_height, min_height;
5806    *
5807    *   mode = clutter_actor_get_request_mode (child);
5808    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5809    *     {
5810    *       clutter_actor_get_preferred_width (child, -1,
5811    *                                          &amp;min_width,
5812    *                                          &amp;natural_width);
5813    *       clutter_actor_get_preferred_height (child, natural_width,
5814    *                                           &amp;min_height,
5815    *                                           &amp;natural_height);
5816    *     }
5817    *   else
5818    *     {
5819    *       clutter_actor_get_preferred_height (child, -1,
5820    *                                           &amp;min_height,
5821    *                                           &amp;natural_height);
5822    *       clutter_actor_get_preferred_width (child, natural_height,
5823    *                                          &amp;min_width,
5824    *                                          &amp;natural_width);
5825    *     }
5826    * ]|
5827    *
5828    * will retrieve the minimum and natural width and height depending on the
5829    * preferred request mode of the #ClutterActor "child".
5830    *
5831    * The clutter_actor_get_preferred_size() function will implement this
5832    * check for you.
5833    *
5834    * Since: 0.8
5835    */
5836   obj_props[PROP_REQUEST_MODE] =
5837     g_param_spec_enum ("request-mode",
5838                        P_("Request Mode"),
5839                        P_("The actor's request mode"),
5840                        CLUTTER_TYPE_REQUEST_MODE,
5841                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5842                        CLUTTER_PARAM_READWRITE);
5843
5844   /**
5845    * ClutterActor:depth:
5846    *
5847    * The position of the actor on the Z axis.
5848    *
5849    * The #ClutterActor:depth property is relative to the parent's
5850    * modelview matrix.
5851    *
5852    * The #ClutterActor:depth property is animatable.
5853    *
5854    * Since: 0.6
5855    */
5856   obj_props[PROP_DEPTH] =
5857     g_param_spec_float ("depth",
5858                         P_("Depth"),
5859                         P_("Position on the Z axis"),
5860                         -G_MAXFLOAT, G_MAXFLOAT,
5861                         0.0,
5862                         G_PARAM_READWRITE |
5863                         G_PARAM_STATIC_STRINGS |
5864                         CLUTTER_PARAM_ANIMATABLE);
5865
5866   /**
5867    * ClutterActor:opacity:
5868    *
5869    * Opacity of an actor, between 0 (fully transparent) and
5870    * 255 (fully opaque)
5871    *
5872    * The #ClutterActor:opacity property is animatable.
5873    */
5874   obj_props[PROP_OPACITY] =
5875     g_param_spec_uint ("opacity",
5876                        P_("Opacity"),
5877                        P_("Opacity of an actor"),
5878                        0, 255,
5879                        255,
5880                        G_PARAM_READWRITE |
5881                        G_PARAM_STATIC_STRINGS |
5882                        CLUTTER_PARAM_ANIMATABLE);
5883
5884   /**
5885    * ClutterActor:offscreen-redirect:
5886    *
5887    * Determines the conditions in which the actor will be redirected
5888    * to an offscreen framebuffer while being painted. For example this
5889    * can be used to cache an actor in a framebuffer or for improved
5890    * handling of transparent actors. See
5891    * clutter_actor_set_offscreen_redirect() for details.
5892    *
5893    * Since: 1.8
5894    */
5895   obj_props[PROP_OFFSCREEN_REDIRECT] =
5896     g_param_spec_flags ("offscreen-redirect",
5897                         P_("Offscreen redirect"),
5898                         P_("Flags controlling when to flatten the actor into a single image"),
5899                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5900                         0,
5901                         CLUTTER_PARAM_READWRITE);
5902
5903   /**
5904    * ClutterActor:visible:
5905    *
5906    * Whether the actor is set to be visible or not
5907    *
5908    * See also #ClutterActor:mapped
5909    */
5910   obj_props[PROP_VISIBLE] =
5911     g_param_spec_boolean ("visible",
5912                           P_("Visible"),
5913                           P_("Whether the actor is visible or not"),
5914                           FALSE,
5915                           CLUTTER_PARAM_READWRITE);
5916
5917   /**
5918    * ClutterActor:mapped:
5919    *
5920    * Whether the actor is mapped (will be painted when the stage
5921    * to which it belongs is mapped)
5922    *
5923    * Since: 1.0
5924    */
5925   obj_props[PROP_MAPPED] =
5926     g_param_spec_boolean ("mapped",
5927                           P_("Mapped"),
5928                           P_("Whether the actor will be painted"),
5929                           FALSE,
5930                           CLUTTER_PARAM_READABLE);
5931
5932   /**
5933    * ClutterActor:realized:
5934    *
5935    * Whether the actor has been realized
5936    *
5937    * Since: 1.0
5938    */
5939   obj_props[PROP_REALIZED] =
5940     g_param_spec_boolean ("realized",
5941                           P_("Realized"),
5942                           P_("Whether the actor has been realized"),
5943                           FALSE,
5944                           CLUTTER_PARAM_READABLE);
5945
5946   /**
5947    * ClutterActor:reactive:
5948    *
5949    * Whether the actor is reactive to events or not
5950    *
5951    * Only reactive actors will emit event-related signals
5952    *
5953    * Since: 0.6
5954    */
5955   obj_props[PROP_REACTIVE] =
5956     g_param_spec_boolean ("reactive",
5957                           P_("Reactive"),
5958                           P_("Whether the actor is reactive to events"),
5959                           FALSE,
5960                           CLUTTER_PARAM_READWRITE);
5961
5962   /**
5963    * ClutterActor:has-clip:
5964    *
5965    * Whether the actor has the #ClutterActor:clip property set or not
5966    */
5967   obj_props[PROP_HAS_CLIP] =
5968     g_param_spec_boolean ("has-clip",
5969                           P_("Has Clip"),
5970                           P_("Whether the actor has a clip set"),
5971                           FALSE,
5972                           CLUTTER_PARAM_READABLE);
5973
5974   /**
5975    * ClutterActor:clip:
5976    *
5977    * The clip region for the actor, in actor-relative coordinates
5978    *
5979    * Every part of the actor outside the clip region will not be
5980    * painted
5981    */
5982   obj_props[PROP_CLIP] =
5983     g_param_spec_boxed ("clip",
5984                         P_("Clip"),
5985                         P_("The clip region for the actor"),
5986                         CLUTTER_TYPE_GEOMETRY,
5987                         CLUTTER_PARAM_READWRITE);
5988
5989   /**
5990    * ClutterActor:name:
5991    *
5992    * The name of the actor
5993    *
5994    * Since: 0.2
5995    */
5996   obj_props[PROP_NAME] =
5997     g_param_spec_string ("name",
5998                          P_("Name"),
5999                          P_("Name of the actor"),
6000                          NULL,
6001                          CLUTTER_PARAM_READWRITE);
6002
6003   /**
6004    * ClutterActor:scale-x:
6005    *
6006    * The horizontal scale of the actor.
6007    *
6008    * The #ClutterActor:scale-x property is animatable.
6009    *
6010    * Since: 0.6
6011    */
6012   obj_props[PROP_SCALE_X] =
6013     g_param_spec_double ("scale-x",
6014                          P_("Scale X"),
6015                          P_("Scale factor on the X axis"),
6016                          0.0, G_MAXDOUBLE,
6017                          1.0,
6018                          G_PARAM_READWRITE |
6019                          G_PARAM_STATIC_STRINGS |
6020                          CLUTTER_PARAM_ANIMATABLE);
6021
6022   /**
6023    * ClutterActor:scale-y:
6024    *
6025    * The vertical scale of the actor.
6026    *
6027    * The #ClutterActor:scale-y property is animatable.
6028    *
6029    * Since: 0.6
6030    */
6031   obj_props[PROP_SCALE_Y] =
6032     g_param_spec_double ("scale-y",
6033                          P_("Scale Y"),
6034                          P_("Scale factor on the Y axis"),
6035                          0.0, G_MAXDOUBLE,
6036                          1.0,
6037                          G_PARAM_READWRITE |
6038                          G_PARAM_STATIC_STRINGS |
6039                          CLUTTER_PARAM_ANIMATABLE);
6040
6041   /**
6042    * ClutterActor:scale-center-x:
6043    *
6044    * The horizontal center point for scaling
6045    *
6046    * Since: 1.0
6047    */
6048   obj_props[PROP_SCALE_CENTER_X] =
6049     g_param_spec_float ("scale-center-x",
6050                         P_("Scale Center X"),
6051                         P_("Horizontal scale center"),
6052                         -G_MAXFLOAT, G_MAXFLOAT,
6053                         0.0,
6054                         CLUTTER_PARAM_READWRITE);
6055
6056   /**
6057    * ClutterActor:scale-center-y:
6058    *
6059    * The vertical center point for scaling
6060    *
6061    * Since: 1.0
6062    */
6063   obj_props[PROP_SCALE_CENTER_Y] =
6064     g_param_spec_float ("scale-center-y",
6065                         P_("Scale Center Y"),
6066                         P_("Vertical scale center"),
6067                         -G_MAXFLOAT, G_MAXFLOAT,
6068                         0.0,
6069                         CLUTTER_PARAM_READWRITE);
6070
6071   /**
6072    * ClutterActor:scale-gravity:
6073    *
6074    * The center point for scaling expressed as a #ClutterGravity
6075    *
6076    * Since: 1.0
6077    */
6078   obj_props[PROP_SCALE_GRAVITY] =
6079     g_param_spec_enum ("scale-gravity",
6080                        P_("Scale Gravity"),
6081                        P_("The center of scaling"),
6082                        CLUTTER_TYPE_GRAVITY,
6083                        CLUTTER_GRAVITY_NONE,
6084                        CLUTTER_PARAM_READWRITE);
6085
6086   /**
6087    * ClutterActor:rotation-angle-x:
6088    *
6089    * The rotation angle on the X axis.
6090    *
6091    * The #ClutterActor:rotation-angle-x property is animatable.
6092    *
6093    * Since: 0.6
6094    */
6095   obj_props[PROP_ROTATION_ANGLE_X] =
6096     g_param_spec_double ("rotation-angle-x",
6097                          P_("Rotation Angle X"),
6098                          P_("The rotation angle on the X axis"),
6099                          -G_MAXDOUBLE, G_MAXDOUBLE,
6100                          0.0,
6101                          G_PARAM_READWRITE |
6102                          G_PARAM_STATIC_STRINGS |
6103                          CLUTTER_PARAM_ANIMATABLE);
6104
6105   /**
6106    * ClutterActor:rotation-angle-y:
6107    *
6108    * The rotation angle on the Y axis
6109    *
6110    * The #ClutterActor:rotation-angle-y property is animatable.
6111    *
6112    * Since: 0.6
6113    */
6114   obj_props[PROP_ROTATION_ANGLE_Y] =
6115     g_param_spec_double ("rotation-angle-y",
6116                          P_("Rotation Angle Y"),
6117                          P_("The rotation angle on the Y axis"),
6118                          -G_MAXDOUBLE, G_MAXDOUBLE,
6119                          0.0,
6120                          G_PARAM_READWRITE |
6121                          G_PARAM_STATIC_STRINGS |
6122                          CLUTTER_PARAM_ANIMATABLE);
6123
6124   /**
6125    * ClutterActor:rotation-angle-z:
6126    *
6127    * The rotation angle on the Z axis
6128    *
6129    * The #ClutterActor:rotation-angle-z property is animatable.
6130    *
6131    * Since: 0.6
6132    */
6133   obj_props[PROP_ROTATION_ANGLE_Z] =
6134     g_param_spec_double ("rotation-angle-z",
6135                          P_("Rotation Angle Z"),
6136                          P_("The rotation angle on the Z axis"),
6137                          -G_MAXDOUBLE, G_MAXDOUBLE,
6138                          0.0,
6139                          G_PARAM_READWRITE |
6140                          G_PARAM_STATIC_STRINGS |
6141                          CLUTTER_PARAM_ANIMATABLE);
6142
6143   /**
6144    * ClutterActor:rotation-center-x:
6145    *
6146    * The rotation center on the X axis.
6147    *
6148    * Since: 0.6
6149    */
6150   obj_props[PROP_ROTATION_CENTER_X] =
6151     g_param_spec_boxed ("rotation-center-x",
6152                         P_("Rotation Center X"),
6153                         P_("The rotation center on the X axis"),
6154                         CLUTTER_TYPE_VERTEX,
6155                         CLUTTER_PARAM_READWRITE);
6156
6157   /**
6158    * ClutterActor:rotation-center-y:
6159    *
6160    * The rotation center on the Y axis.
6161    *
6162    * Since: 0.6
6163    */
6164   obj_props[PROP_ROTATION_CENTER_Y] =
6165     g_param_spec_boxed ("rotation-center-y",
6166                         P_("Rotation Center Y"),
6167                         P_("The rotation center on the Y axis"),
6168                         CLUTTER_TYPE_VERTEX,
6169                         CLUTTER_PARAM_READWRITE);
6170
6171   /**
6172    * ClutterActor:rotation-center-z:
6173    *
6174    * The rotation center on the Z axis.
6175    *
6176    * Since: 0.6
6177    */
6178   obj_props[PROP_ROTATION_CENTER_Z] =
6179     g_param_spec_boxed ("rotation-center-z",
6180                         P_("Rotation Center Z"),
6181                         P_("The rotation center on the Z axis"),
6182                         CLUTTER_TYPE_VERTEX,
6183                         CLUTTER_PARAM_READWRITE);
6184
6185   /**
6186    * ClutterActor:rotation-center-z-gravity:
6187    *
6188    * The rotation center on the Z axis expressed as a #ClutterGravity.
6189    *
6190    * Since: 1.0
6191    */
6192   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6193     g_param_spec_enum ("rotation-center-z-gravity",
6194                        P_("Rotation Center Z Gravity"),
6195                        P_("Center point for rotation around the Z axis"),
6196                        CLUTTER_TYPE_GRAVITY,
6197                        CLUTTER_GRAVITY_NONE,
6198                        CLUTTER_PARAM_READWRITE);
6199
6200   /**
6201    * ClutterActor:anchor-x:
6202    *
6203    * The X coordinate of an actor's anchor point, relative to
6204    * the actor coordinate space, in pixels
6205    *
6206    * Since: 0.8
6207    */
6208   obj_props[PROP_ANCHOR_X] =
6209     g_param_spec_float ("anchor-x",
6210                         P_("Anchor X"),
6211                         P_("X coordinate of the anchor point"),
6212                         -G_MAXFLOAT, G_MAXFLOAT,
6213                         0,
6214                         CLUTTER_PARAM_READWRITE);
6215
6216   /**
6217    * ClutterActor:anchor-y:
6218    *
6219    * The Y coordinate of an actor's anchor point, relative to
6220    * the actor coordinate space, in pixels
6221    *
6222    * Since: 0.8
6223    */
6224   obj_props[PROP_ANCHOR_Y] =
6225     g_param_spec_float ("anchor-y",
6226                         P_("Anchor Y"),
6227                         P_("Y coordinate of the anchor point"),
6228                         -G_MAXFLOAT, G_MAXFLOAT,
6229                         0,
6230                         CLUTTER_PARAM_READWRITE);
6231
6232   /**
6233    * ClutterActor:anchor-gravity:
6234    *
6235    * The anchor point expressed as a #ClutterGravity
6236    *
6237    * Since: 1.0
6238    */
6239   obj_props[PROP_ANCHOR_GRAVITY] =
6240     g_param_spec_enum ("anchor-gravity",
6241                        P_("Anchor Gravity"),
6242                        P_("The anchor point as a ClutterGravity"),
6243                        CLUTTER_TYPE_GRAVITY,
6244                        CLUTTER_GRAVITY_NONE,
6245                        CLUTTER_PARAM_READWRITE);
6246
6247   /**
6248    * ClutterActor:show-on-set-parent:
6249    *
6250    * If %TRUE, the actor is automatically shown when parented.
6251    *
6252    * Calling clutter_actor_hide() on an actor which has not been
6253    * parented will set this property to %FALSE as a side effect.
6254    *
6255    * Since: 0.8
6256    */
6257   obj_props[PROP_SHOW_ON_SET_PARENT] =
6258     g_param_spec_boolean ("show-on-set-parent",
6259                           P_("Show on set parent"),
6260                           P_("Whether the actor is shown when parented"),
6261                           TRUE,
6262                           CLUTTER_PARAM_READWRITE);
6263
6264   /**
6265    * ClutterActor:clip-to-allocation:
6266    *
6267    * Whether the clip region should track the allocated area
6268    * of the actor.
6269    *
6270    * This property is ignored if a clip area has been explicitly
6271    * set using clutter_actor_set_clip().
6272    *
6273    * Since: 1.0
6274    */
6275   obj_props[PROP_CLIP_TO_ALLOCATION] =
6276     g_param_spec_boolean ("clip-to-allocation",
6277                           P_("Clip to Allocation"),
6278                           P_("Sets the clip region to track the actor's allocation"),
6279                           FALSE,
6280                           CLUTTER_PARAM_READWRITE);
6281
6282   /**
6283    * ClutterActor:text-direction:
6284    *
6285    * The direction of the text inside a #ClutterActor.
6286    *
6287    * Since: 1.0
6288    */
6289   obj_props[PROP_TEXT_DIRECTION] =
6290     g_param_spec_enum ("text-direction",
6291                        P_("Text Direction"),
6292                        P_("Direction of the text"),
6293                        CLUTTER_TYPE_TEXT_DIRECTION,
6294                        CLUTTER_TEXT_DIRECTION_LTR,
6295                        CLUTTER_PARAM_READWRITE);
6296
6297   /**
6298    * ClutterActor:has-pointer:
6299    *
6300    * Whether the actor contains the pointer of a #ClutterInputDevice
6301    * or not.
6302    *
6303    * Since: 1.2
6304    */
6305   obj_props[PROP_HAS_POINTER] =
6306     g_param_spec_boolean ("has-pointer",
6307                           P_("Has Pointer"),
6308                           P_("Whether the actor contains the pointer of an input device"),
6309                           FALSE,
6310                           CLUTTER_PARAM_READABLE);
6311
6312   /**
6313    * ClutterActor:actions:
6314    *
6315    * Adds a #ClutterAction to the actor
6316    *
6317    * Since: 1.4
6318    */
6319   obj_props[PROP_ACTIONS] =
6320     g_param_spec_object ("actions",
6321                          P_("Actions"),
6322                          P_("Adds an action to the actor"),
6323                          CLUTTER_TYPE_ACTION,
6324                          CLUTTER_PARAM_WRITABLE);
6325
6326   /**
6327    * ClutterActor:constraints:
6328    *
6329    * Adds a #ClutterConstraint to the actor
6330    *
6331    * Since: 1.4
6332    */
6333   obj_props[PROP_CONSTRAINTS] =
6334     g_param_spec_object ("constraints",
6335                          P_("Constraints"),
6336                          P_("Adds a constraint to the actor"),
6337                          CLUTTER_TYPE_CONSTRAINT,
6338                          CLUTTER_PARAM_WRITABLE);
6339
6340   /**
6341    * ClutterActor:effect:
6342    *
6343    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6344    *
6345    * Since: 1.4
6346    */
6347   obj_props[PROP_EFFECT] =
6348     g_param_spec_object ("effect",
6349                          P_("Effect"),
6350                          P_("Add an effect to be applied on the actor"),
6351                          CLUTTER_TYPE_EFFECT,
6352                          CLUTTER_PARAM_WRITABLE);
6353
6354   /**
6355    * ClutterActor:layout-manager:
6356    *
6357    * A delegate object for controlling the layout of the children of
6358    * an actor.
6359    *
6360    * Since: 1.10
6361    */
6362   obj_props[PROP_LAYOUT_MANAGER] =
6363     g_param_spec_object ("layout-manager",
6364                          P_("Layout Manager"),
6365                          P_("The object controlling the layout of an actor's children"),
6366                          CLUTTER_TYPE_LAYOUT_MANAGER,
6367                          CLUTTER_PARAM_READWRITE);
6368
6369
6370   /**
6371    * ClutterActor:x-align:
6372    *
6373    * The alignment of an actor on the X axis, if the actor has been given
6374    * extra space for its allocation.
6375    *
6376    * Since: 1.10
6377    */
6378   obj_props[PROP_X_ALIGN] =
6379     g_param_spec_enum ("x-align",
6380                        P_("X Alignment"),
6381                        P_("The alignment of the actor on the X axis within its allocation"),
6382                        CLUTTER_TYPE_ACTOR_ALIGN,
6383                        CLUTTER_ACTOR_ALIGN_FILL,
6384                        CLUTTER_PARAM_READWRITE);
6385
6386   /**
6387    * ClutterActor:y-align:
6388    *
6389    * The alignment of an actor on the Y axis, if the actor has been given
6390    * extra space for its allocation.
6391    *
6392    * Since: 1.10
6393    */
6394   obj_props[PROP_Y_ALIGN] =
6395     g_param_spec_enum ("y-align",
6396                        P_("Y Alignment"),
6397                        P_("The alignment of the actor on the Y axis within its allocation"),
6398                        CLUTTER_TYPE_ACTOR_ALIGN,
6399                        CLUTTER_ACTOR_ALIGN_FILL,
6400                        CLUTTER_PARAM_READWRITE);
6401
6402   /**
6403    * ClutterActor:margin-top:
6404    *
6405    * The margin (in pixels) from the top of the actor.
6406    *
6407    * This property adds a margin to the actor's preferred size; the margin
6408    * will be automatically taken into account when allocating the actor.
6409    *
6410    * Since: 1.10
6411    */
6412   obj_props[PROP_MARGIN_TOP] =
6413     g_param_spec_float ("margin-top",
6414                         P_("Margin Top"),
6415                         P_("Extra space at the top"),
6416                         0.0, G_MAXFLOAT,
6417                         0.0,
6418                         CLUTTER_PARAM_READWRITE);
6419
6420   /**
6421    * ClutterActor:margin-bottom:
6422    *
6423    * The margin (in pixels) from the bottom of the actor.
6424    *
6425    * This property adds a margin to the actor's preferred size; the margin
6426    * will be automatically taken into account when allocating the actor.
6427    *
6428    * Since: 1.10
6429    */
6430   obj_props[PROP_MARGIN_BOTTOM] =
6431     g_param_spec_float ("margin-bottom",
6432                         P_("Margin Bottom"),
6433                         P_("Extra space at the bottom"),
6434                         0.0, G_MAXFLOAT,
6435                         0.0,
6436                         CLUTTER_PARAM_READWRITE);
6437
6438   /**
6439    * ClutterActor:margin-left:
6440    *
6441    * The margin (in pixels) from the left of the actor.
6442    *
6443    * This property adds a margin to the actor's preferred size; the margin
6444    * will be automatically taken into account when allocating the actor.
6445    *
6446    * Since: 1.10
6447    */
6448   obj_props[PROP_MARGIN_LEFT] =
6449     g_param_spec_float ("margin-left",
6450                         P_("Margin Left"),
6451                         P_("Extra space at the left"),
6452                         0.0, G_MAXFLOAT,
6453                         0.0,
6454                         CLUTTER_PARAM_READWRITE);
6455
6456   /**
6457    * ClutterActor:margin-right:
6458    *
6459    * The margin (in pixels) from the right of the actor.
6460    *
6461    * This property adds a margin to the actor's preferred size; the margin
6462    * will be automatically taken into account when allocating the actor.
6463    *
6464    * Since: 1.10
6465    */
6466   obj_props[PROP_MARGIN_RIGHT] =
6467     g_param_spec_float ("margin-right",
6468                         P_("Margin Right"),
6469                         P_("Extra space at the right"),
6470                         0.0, G_MAXFLOAT,
6471                         0.0,
6472                         CLUTTER_PARAM_READWRITE);
6473
6474   /**
6475    * ClutterActor:background-color-set:
6476    *
6477    * Whether the #ClutterActor:background-color property has been set.
6478    *
6479    * Since: 1.10
6480    */
6481   obj_props[PROP_BACKGROUND_COLOR_SET] =
6482     g_param_spec_boolean ("background-color-set",
6483                           P_("Background Color Set"),
6484                           P_("Whether the background color is set"),
6485                           FALSE,
6486                           CLUTTER_PARAM_READABLE);
6487
6488   /**
6489    * ClutterActor:background-color:
6490    *
6491    * Paints a solid fill of the actor's allocation using the specified
6492    * color.
6493    *
6494    * The #ClutterActor:background-color property is animatable.
6495    *
6496    * Since: 1.10
6497    */
6498   obj_props[PROP_BACKGROUND_COLOR] =
6499     clutter_param_spec_color ("background-color",
6500                               P_("Background color"),
6501                               P_("The actor's background color"),
6502                               CLUTTER_COLOR_Transparent,
6503                               G_PARAM_READWRITE |
6504                               G_PARAM_STATIC_STRINGS |
6505                               CLUTTER_PARAM_ANIMATABLE);
6506
6507   /**
6508    * ClutterActor:first-child:
6509    *
6510    * The actor's first child.
6511    *
6512    * Since: 1.10
6513    */
6514   obj_props[PROP_FIRST_CHILD] =
6515     g_param_spec_object ("first-child",
6516                          P_("First Child"),
6517                          P_("The actor's first child"),
6518                          CLUTTER_TYPE_ACTOR,
6519                          CLUTTER_PARAM_READABLE);
6520
6521   /**
6522    * ClutterActor:last-child:
6523    *
6524    * The actor's last child.
6525    *
6526    * Since: 1.10
6527    */
6528   obj_props[PROP_LAST_CHILD] =
6529     g_param_spec_object ("last-child",
6530                          P_("Last Child"),
6531                          P_("The actor's last child"),
6532                          CLUTTER_TYPE_ACTOR,
6533                          CLUTTER_PARAM_READABLE);
6534
6535   /**
6536    * ClutterActor:content:
6537    *
6538    * The #ClutterContent implementation that controls the content
6539    * of the actor.
6540    *
6541    * Since: 1.10
6542    */
6543   obj_props[PROP_CONTENT] =
6544     g_param_spec_object ("content",
6545                          P_("Content"),
6546                          P_("Delegate object for painting the actor's content"),
6547                          CLUTTER_TYPE_CONTENT,
6548                          CLUTTER_PARAM_READWRITE);
6549
6550   /**
6551    * ClutterActor:content-gravity:
6552    *
6553    * The alignment that should be honoured by the #ClutterContent
6554    * set with the #ClutterActor:content property.
6555    *
6556    * Changing the value of this property will change the bounding box of
6557    * the content; you can use the #ClutterActor:content-box property to
6558    * get the position and size of the content within the actor's
6559    * allocation.
6560    *
6561    * This property is meaningful only for #ClutterContent implementations
6562    * that have a preferred size, and if the preferred size is smaller than
6563    * the actor's allocation.
6564    *
6565    * The #ClutterActor:content-gravity property is animatable.
6566    *
6567    * Since: 1.10
6568    */
6569   obj_props[PROP_CONTENT_GRAVITY] =
6570     g_param_spec_enum ("content-gravity",
6571                        P_("Content Gravity"),
6572                        P_("Alignment of the actor's content"),
6573                        CLUTTER_TYPE_CONTENT_GRAVITY,
6574                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6575                        CLUTTER_PARAM_READWRITE);
6576
6577   /**
6578    * ClutterActor:content-box:
6579    *
6580    * The bounding box for the #ClutterContent used by the actor.
6581    *
6582    * The value of this property is controlled by the #ClutterActor:allocation
6583    * and #ClutterActor:content-gravity properties of #ClutterActor.
6584    *
6585    * The bounding box for the content is guaranteed to never exceed the
6586    * allocation's of the actor.
6587    *
6588    * Since: 1.10
6589    */
6590   obj_props[PROP_CONTENT_BOX] =
6591     g_param_spec_boxed ("content-box",
6592                         P_("Content Box"),
6593                         P_("The bounding box of the actor's content"),
6594                         CLUTTER_TYPE_ACTOR_BOX,
6595                         G_PARAM_READABLE |
6596                         G_PARAM_STATIC_STRINGS |
6597                         CLUTTER_PARAM_ANIMATABLE);
6598
6599   obj_props[PROP_MINIFICATION_FILTER] =
6600     g_param_spec_enum ("minification-filter",
6601                        P_("Minification Filter"),
6602                        P_("The filter used when reducing the size of the content"),
6603                        CLUTTER_TYPE_SCALING_FILTER,
6604                        CLUTTER_SCALING_FILTER_LINEAR,
6605                        CLUTTER_PARAM_READWRITE);
6606
6607   obj_props[PROP_MAGNIFICATION_FILTER] =
6608     g_param_spec_enum ("magnification-filter",
6609                        P_("Magnification Filter"),
6610                        P_("The filter used when increasing the size of the content"),
6611                        CLUTTER_TYPE_SCALING_FILTER,
6612                        CLUTTER_SCALING_FILTER_LINEAR,
6613                        CLUTTER_PARAM_READWRITE);
6614
6615   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6616
6617   /**
6618    * ClutterActor::destroy:
6619    * @actor: the #ClutterActor which emitted the signal
6620    *
6621    * The ::destroy signal notifies that all references held on the
6622    * actor which emitted it should be released.
6623    *
6624    * The ::destroy signal should be used by all holders of a reference
6625    * on @actor.
6626    *
6627    * This signal might result in the finalization of the #ClutterActor
6628    * if all references are released.
6629    *
6630    * Composite actors and actors implementing the #ClutterContainer
6631    * interface should override the default implementation of the
6632    * class handler of this signal and call clutter_actor_destroy() on
6633    * their children. When overriding the default class handler, it is
6634    * required to chain up to the parent's implementation.
6635    *
6636    * Since: 0.2
6637    */
6638   actor_signals[DESTROY] =
6639     g_signal_new (I_("destroy"),
6640                   G_TYPE_FROM_CLASS (object_class),
6641                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6642                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6643                   NULL, NULL,
6644                   _clutter_marshal_VOID__VOID,
6645                   G_TYPE_NONE, 0);
6646   /**
6647    * ClutterActor::show:
6648    * @actor: the object which received the signal
6649    *
6650    * The ::show signal is emitted when an actor is visible and
6651    * rendered on the stage.
6652    *
6653    * Since: 0.2
6654    */
6655   actor_signals[SHOW] =
6656     g_signal_new (I_("show"),
6657                   G_TYPE_FROM_CLASS (object_class),
6658                   G_SIGNAL_RUN_FIRST,
6659                   G_STRUCT_OFFSET (ClutterActorClass, show),
6660                   NULL, NULL,
6661                   _clutter_marshal_VOID__VOID,
6662                   G_TYPE_NONE, 0);
6663   /**
6664    * ClutterActor::hide:
6665    * @actor: the object which received the signal
6666    *
6667    * The ::hide signal is emitted when an actor is no longer rendered
6668    * on the stage.
6669    *
6670    * Since: 0.2
6671    */
6672   actor_signals[HIDE] =
6673     g_signal_new (I_("hide"),
6674                   G_TYPE_FROM_CLASS (object_class),
6675                   G_SIGNAL_RUN_FIRST,
6676                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6677                   NULL, NULL,
6678                   _clutter_marshal_VOID__VOID,
6679                   G_TYPE_NONE, 0);
6680   /**
6681    * ClutterActor::parent-set:
6682    * @actor: the object which received the signal
6683    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6684    *
6685    * This signal is emitted when the parent of the actor changes.
6686    *
6687    * Since: 0.2
6688    */
6689   actor_signals[PARENT_SET] =
6690     g_signal_new (I_("parent-set"),
6691                   G_TYPE_FROM_CLASS (object_class),
6692                   G_SIGNAL_RUN_LAST,
6693                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6694                   NULL, NULL,
6695                   _clutter_marshal_VOID__OBJECT,
6696                   G_TYPE_NONE, 1,
6697                   CLUTTER_TYPE_ACTOR);
6698
6699   /**
6700    * ClutterActor::queue-redraw:
6701    * @actor: the actor we're bubbling the redraw request through
6702    * @origin: the actor which initiated the redraw request
6703    *
6704    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6705    * is called on @origin.
6706    *
6707    * The default implementation for #ClutterActor chains up to the
6708    * parent actor and queues a redraw on the parent, thus "bubbling"
6709    * the redraw queue up through the actor graph. The default
6710    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6711    * in a main loop idle handler.
6712    *
6713    * Note that the @origin actor may be the stage, or a container; it
6714    * does not have to be a leaf node in the actor graph.
6715    *
6716    * Toolkits embedding a #ClutterStage which require a redraw and
6717    * relayout cycle can stop the emission of this signal using the
6718    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6719    * themselves, like:
6720    *
6721    * |[
6722    *   static void
6723    *   on_redraw_complete (gpointer data)
6724    *   {
6725    *     ClutterStage *stage = data;
6726    *
6727    *     /&ast; execute the Clutter drawing pipeline &ast;/
6728    *     clutter_stage_ensure_redraw (stage);
6729    *   }
6730    *
6731    *   static void
6732    *   on_stage_queue_redraw (ClutterStage *stage)
6733    *   {
6734    *     /&ast; this prevents the default handler to run &ast;/
6735    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6736    *
6737    *     /&ast; queue a redraw with the host toolkit and call
6738    *      &ast; a function when the redraw has been completed
6739    *      &ast;/
6740    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6741    *   }
6742    * ]|
6743    *
6744    * <note><para>This signal is emitted before the Clutter paint
6745    * pipeline is executed. If you want to know when the pipeline has
6746    * been completed you should connect to the ::paint signal on the
6747    * Stage with g_signal_connect_after().</para></note>
6748    *
6749    * Since: 1.0
6750    */
6751   actor_signals[QUEUE_REDRAW] =
6752     g_signal_new (I_("queue-redraw"),
6753                   G_TYPE_FROM_CLASS (object_class),
6754                   G_SIGNAL_RUN_LAST |
6755                   G_SIGNAL_NO_HOOKS,
6756                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6757                   NULL, NULL,
6758                   _clutter_marshal_VOID__OBJECT,
6759                   G_TYPE_NONE, 1,
6760                   CLUTTER_TYPE_ACTOR);
6761
6762   /**
6763    * ClutterActor::queue-relayout
6764    * @actor: the actor being queued for relayout
6765    *
6766    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6767    * is called on an actor.
6768    *
6769    * The default implementation for #ClutterActor chains up to the
6770    * parent actor and queues a relayout on the parent, thus "bubbling"
6771    * the relayout queue up through the actor graph.
6772    *
6773    * The main purpose of this signal is to allow relayout to be propagated
6774    * properly in the procense of #ClutterClone actors. Applications will
6775    * not normally need to connect to this signal.
6776    *
6777    * Since: 1.2
6778    */
6779   actor_signals[QUEUE_RELAYOUT] =
6780     g_signal_new (I_("queue-relayout"),
6781                   G_TYPE_FROM_CLASS (object_class),
6782                   G_SIGNAL_RUN_LAST |
6783                   G_SIGNAL_NO_HOOKS,
6784                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6785                   NULL, NULL,
6786                   _clutter_marshal_VOID__VOID,
6787                   G_TYPE_NONE, 0);
6788
6789   /**
6790    * ClutterActor::event:
6791    * @actor: the actor which received the event
6792    * @event: a #ClutterEvent
6793    *
6794    * The ::event signal is emitted each time an event is received
6795    * by the @actor. This signal will be emitted on every actor,
6796    * following the hierarchy chain, until it reaches the top-level
6797    * container (the #ClutterStage).
6798    *
6799    * Return value: %TRUE if the event has been handled by the actor,
6800    *   or %FALSE to continue the emission.
6801    *
6802    * Since: 0.6
6803    */
6804   actor_signals[EVENT] =
6805     g_signal_new (I_("event"),
6806                   G_TYPE_FROM_CLASS (object_class),
6807                   G_SIGNAL_RUN_LAST,
6808                   G_STRUCT_OFFSET (ClutterActorClass, event),
6809                   _clutter_boolean_handled_accumulator, NULL,
6810                   _clutter_marshal_BOOLEAN__BOXED,
6811                   G_TYPE_BOOLEAN, 1,
6812                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6813   /**
6814    * ClutterActor::button-press-event:
6815    * @actor: the actor which received the event
6816    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6817    *
6818    * The ::button-press-event signal is emitted each time a mouse button
6819    * is pressed on @actor.
6820    *
6821    * Return value: %TRUE if the event has been handled by the actor,
6822    *   or %FALSE to continue the emission.
6823    *
6824    * Since: 0.6
6825    */
6826   actor_signals[BUTTON_PRESS_EVENT] =
6827     g_signal_new (I_("button-press-event"),
6828                   G_TYPE_FROM_CLASS (object_class),
6829                   G_SIGNAL_RUN_LAST,
6830                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6831                   _clutter_boolean_handled_accumulator, NULL,
6832                   _clutter_marshal_BOOLEAN__BOXED,
6833                   G_TYPE_BOOLEAN, 1,
6834                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6835   /**
6836    * ClutterActor::button-release-event:
6837    * @actor: the actor which received the event
6838    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6839    *
6840    * The ::button-release-event signal is emitted each time a mouse button
6841    * is released on @actor.
6842    *
6843    * Return value: %TRUE if the event has been handled by the actor,
6844    *   or %FALSE to continue the emission.
6845    *
6846    * Since: 0.6
6847    */
6848   actor_signals[BUTTON_RELEASE_EVENT] =
6849     g_signal_new (I_("button-release-event"),
6850                   G_TYPE_FROM_CLASS (object_class),
6851                   G_SIGNAL_RUN_LAST,
6852                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6853                   _clutter_boolean_handled_accumulator, NULL,
6854                   _clutter_marshal_BOOLEAN__BOXED,
6855                   G_TYPE_BOOLEAN, 1,
6856                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6857   /**
6858    * ClutterActor::scroll-event:
6859    * @actor: the actor which received the event
6860    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6861    *
6862    * The ::scroll-event signal is emitted each time the mouse is
6863    * scrolled on @actor
6864    *
6865    * Return value: %TRUE if the event has been handled by the actor,
6866    *   or %FALSE to continue the emission.
6867    *
6868    * Since: 0.6
6869    */
6870   actor_signals[SCROLL_EVENT] =
6871     g_signal_new (I_("scroll-event"),
6872                   G_TYPE_FROM_CLASS (object_class),
6873                   G_SIGNAL_RUN_LAST,
6874                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6875                   _clutter_boolean_handled_accumulator, NULL,
6876                   _clutter_marshal_BOOLEAN__BOXED,
6877                   G_TYPE_BOOLEAN, 1,
6878                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6879   /**
6880    * ClutterActor::key-press-event:
6881    * @actor: the actor which received the event
6882    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6883    *
6884    * The ::key-press-event signal is emitted each time a keyboard button
6885    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6886    *
6887    * Return value: %TRUE if the event has been handled by the actor,
6888    *   or %FALSE to continue the emission.
6889    *
6890    * Since: 0.6
6891    */
6892   actor_signals[KEY_PRESS_EVENT] =
6893     g_signal_new (I_("key-press-event"),
6894                   G_TYPE_FROM_CLASS (object_class),
6895                   G_SIGNAL_RUN_LAST,
6896                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6897                   _clutter_boolean_handled_accumulator, NULL,
6898                   _clutter_marshal_BOOLEAN__BOXED,
6899                   G_TYPE_BOOLEAN, 1,
6900                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6901   /**
6902    * ClutterActor::key-release-event:
6903    * @actor: the actor which received the event
6904    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6905    *
6906    * The ::key-release-event signal is emitted each time a keyboard button
6907    * is released while @actor has key focus (see
6908    * clutter_stage_set_key_focus()).
6909    *
6910    * Return value: %TRUE if the event has been handled by the actor,
6911    *   or %FALSE to continue the emission.
6912    *
6913    * Since: 0.6
6914    */
6915   actor_signals[KEY_RELEASE_EVENT] =
6916     g_signal_new (I_("key-release-event"),
6917                   G_TYPE_FROM_CLASS (object_class),
6918                   G_SIGNAL_RUN_LAST,
6919                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6920                   _clutter_boolean_handled_accumulator, NULL,
6921                   _clutter_marshal_BOOLEAN__BOXED,
6922                   G_TYPE_BOOLEAN, 1,
6923                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6924   /**
6925    * ClutterActor::motion-event:
6926    * @actor: the actor which received the event
6927    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6928    *
6929    * The ::motion-event signal is emitted each time the mouse pointer is
6930    * moved over @actor.
6931    *
6932    * Return value: %TRUE if the event has been handled by the actor,
6933    *   or %FALSE to continue the emission.
6934    *
6935    * Since: 0.6
6936    */
6937   actor_signals[MOTION_EVENT] =
6938     g_signal_new (I_("motion-event"),
6939                   G_TYPE_FROM_CLASS (object_class),
6940                   G_SIGNAL_RUN_LAST,
6941                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6942                   _clutter_boolean_handled_accumulator, NULL,
6943                   _clutter_marshal_BOOLEAN__BOXED,
6944                   G_TYPE_BOOLEAN, 1,
6945                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6946
6947   /**
6948    * ClutterActor::key-focus-in:
6949    * @actor: the actor which now has key focus
6950    *
6951    * The ::key-focus-in signal is emitted when @actor receives key focus.
6952    *
6953    * Since: 0.6
6954    */
6955   actor_signals[KEY_FOCUS_IN] =
6956     g_signal_new (I_("key-focus-in"),
6957                   G_TYPE_FROM_CLASS (object_class),
6958                   G_SIGNAL_RUN_LAST,
6959                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6960                   NULL, NULL,
6961                   _clutter_marshal_VOID__VOID,
6962                   G_TYPE_NONE, 0);
6963
6964   /**
6965    * ClutterActor::key-focus-out:
6966    * @actor: the actor which now has key focus
6967    *
6968    * The ::key-focus-out signal is emitted when @actor loses key focus.
6969    *
6970    * Since: 0.6
6971    */
6972   actor_signals[KEY_FOCUS_OUT] =
6973     g_signal_new (I_("key-focus-out"),
6974                   G_TYPE_FROM_CLASS (object_class),
6975                   G_SIGNAL_RUN_LAST,
6976                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6977                   NULL, NULL,
6978                   _clutter_marshal_VOID__VOID,
6979                   G_TYPE_NONE, 0);
6980
6981   /**
6982    * ClutterActor::enter-event:
6983    * @actor: the actor which the pointer has entered.
6984    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6985    *
6986    * The ::enter-event signal is emitted when the pointer enters the @actor
6987    *
6988    * Return value: %TRUE if the event has been handled by the actor,
6989    *   or %FALSE to continue the emission.
6990    *
6991    * Since: 0.6
6992    */
6993   actor_signals[ENTER_EVENT] =
6994     g_signal_new (I_("enter-event"),
6995                   G_TYPE_FROM_CLASS (object_class),
6996                   G_SIGNAL_RUN_LAST,
6997                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6998                   _clutter_boolean_handled_accumulator, NULL,
6999                   _clutter_marshal_BOOLEAN__BOXED,
7000                   G_TYPE_BOOLEAN, 1,
7001                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7002
7003   /**
7004    * ClutterActor::leave-event:
7005    * @actor: the actor which the pointer has left
7006    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
7007    *
7008    * The ::leave-event signal is emitted when the pointer leaves the @actor.
7009    *
7010    * Return value: %TRUE if the event has been handled by the actor,
7011    *   or %FALSE to continue the emission.
7012    *
7013    * Since: 0.6
7014    */
7015   actor_signals[LEAVE_EVENT] =
7016     g_signal_new (I_("leave-event"),
7017                   G_TYPE_FROM_CLASS (object_class),
7018                   G_SIGNAL_RUN_LAST,
7019                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
7020                   _clutter_boolean_handled_accumulator, NULL,
7021                   _clutter_marshal_BOOLEAN__BOXED,
7022                   G_TYPE_BOOLEAN, 1,
7023                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7024
7025   /**
7026    * ClutterActor::captured-event:
7027    * @actor: the actor which received the signal
7028    * @event: a #ClutterEvent
7029    *
7030    * The ::captured-event signal is emitted when an event is captured
7031    * by Clutter. This signal will be emitted starting from the top-level
7032    * container (the #ClutterStage) to the actor which received the event
7033    * going down the hierarchy. This signal can be used to intercept every
7034    * event before the specialized events (like
7035    * ClutterActor::button-press-event or ::key-released-event) are
7036    * emitted.
7037    *
7038    * Return value: %TRUE if the event has been handled by the actor,
7039    *   or %FALSE to continue the emission.
7040    *
7041    * Since: 0.6
7042    */
7043   actor_signals[CAPTURED_EVENT] =
7044     g_signal_new (I_("captured-event"),
7045                   G_TYPE_FROM_CLASS (object_class),
7046                   G_SIGNAL_RUN_LAST,
7047                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
7048                   _clutter_boolean_handled_accumulator, NULL,
7049                   _clutter_marshal_BOOLEAN__BOXED,
7050                   G_TYPE_BOOLEAN, 1,
7051                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
7052
7053   /**
7054    * ClutterActor::paint:
7055    * @actor: the #ClutterActor that received the signal
7056    *
7057    * The ::paint signal is emitted each time an actor is being painted.
7058    *
7059    * Subclasses of #ClutterActor should override the class signal handler
7060    * and paint themselves in that function.
7061    *
7062    * It is possible to connect a handler to the ::paint signal in order
7063    * to set up some custom aspect of a paint.
7064    *
7065    * Since: 0.8
7066    */
7067   actor_signals[PAINT] =
7068     g_signal_new (I_("paint"),
7069                   G_TYPE_FROM_CLASS (object_class),
7070                   G_SIGNAL_RUN_LAST |
7071                   G_SIGNAL_NO_HOOKS,
7072                   G_STRUCT_OFFSET (ClutterActorClass, paint),
7073                   NULL, NULL,
7074                   _clutter_marshal_VOID__VOID,
7075                   G_TYPE_NONE, 0);
7076   /**
7077    * ClutterActor::realize:
7078    * @actor: the #ClutterActor that received the signal
7079    *
7080    * The ::realize signal is emitted each time an actor is being
7081    * realized.
7082    *
7083    * Since: 0.8
7084    */
7085   actor_signals[REALIZE] =
7086     g_signal_new (I_("realize"),
7087                   G_TYPE_FROM_CLASS (object_class),
7088                   G_SIGNAL_RUN_LAST,
7089                   G_STRUCT_OFFSET (ClutterActorClass, realize),
7090                   NULL, NULL,
7091                   _clutter_marshal_VOID__VOID,
7092                   G_TYPE_NONE, 0);
7093   /**
7094    * ClutterActor::unrealize:
7095    * @actor: the #ClutterActor that received the signal
7096    *
7097    * The ::unrealize signal is emitted each time an actor is being
7098    * unrealized.
7099    *
7100    * Since: 0.8
7101    */
7102   actor_signals[UNREALIZE] =
7103     g_signal_new (I_("unrealize"),
7104                   G_TYPE_FROM_CLASS (object_class),
7105                   G_SIGNAL_RUN_LAST,
7106                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
7107                   NULL, NULL,
7108                   _clutter_marshal_VOID__VOID,
7109                   G_TYPE_NONE, 0);
7110
7111   /**
7112    * ClutterActor::pick:
7113    * @actor: the #ClutterActor that received the signal
7114    * @color: the #ClutterColor to be used when picking
7115    *
7116    * The ::pick signal is emitted each time an actor is being painted
7117    * in "pick mode". The pick mode is used to identify the actor during
7118    * the event handling phase, or by clutter_stage_get_actor_at_pos().
7119    * The actor should paint its shape using the passed @pick_color.
7120    *
7121    * Subclasses of #ClutterActor should override the class signal handler
7122    * and paint themselves in that function.
7123    *
7124    * It is possible to connect a handler to the ::pick signal in order
7125    * to set up some custom aspect of a paint in pick mode.
7126    *
7127    * Since: 1.0
7128    */
7129   actor_signals[PICK] =
7130     g_signal_new (I_("pick"),
7131                   G_TYPE_FROM_CLASS (object_class),
7132                   G_SIGNAL_RUN_LAST,
7133                   G_STRUCT_OFFSET (ClutterActorClass, pick),
7134                   NULL, NULL,
7135                   _clutter_marshal_VOID__BOXED,
7136                   G_TYPE_NONE, 1,
7137                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7138
7139   /**
7140    * ClutterActor::allocation-changed:
7141    * @actor: the #ClutterActor that emitted the signal
7142    * @box: a #ClutterActorBox with the new allocation
7143    * @flags: #ClutterAllocationFlags for the allocation
7144    *
7145    * The ::allocation-changed signal is emitted when the
7146    * #ClutterActor:allocation property changes. Usually, application
7147    * code should just use the notifications for the :allocation property
7148    * but if you want to track the allocation flags as well, for instance
7149    * to know whether the absolute origin of @actor changed, then you might
7150    * want use this signal instead.
7151    *
7152    * Since: 1.0
7153    */
7154   actor_signals[ALLOCATION_CHANGED] =
7155     g_signal_new (I_("allocation-changed"),
7156                   G_TYPE_FROM_CLASS (object_class),
7157                   G_SIGNAL_RUN_LAST,
7158                   0,
7159                   NULL, NULL,
7160                   _clutter_marshal_VOID__BOXED_FLAGS,
7161                   G_TYPE_NONE, 2,
7162                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7163                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7164
7165   /**
7166    * ClutterActor::transitions-completed:
7167    * @actor: a #ClutterActor
7168    *
7169    * The ::transitions-completed signal is emitted once all transitions
7170    * involving @actor are complete.
7171    *
7172    * Since: 1.10
7173    */
7174   actor_signals[TRANSITIONS_COMPLETED] =
7175     g_signal_new (I_("transitions-completed"),
7176                   G_TYPE_FROM_CLASS (object_class),
7177                   G_SIGNAL_RUN_LAST,
7178                   0,
7179                   NULL, NULL,
7180                   _clutter_marshal_VOID__VOID,
7181                   G_TYPE_NONE, 0);
7182 }
7183
7184 static void
7185 clutter_actor_init (ClutterActor *self)
7186 {
7187   ClutterActorPrivate *priv;
7188
7189   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7190
7191   priv->id = _clutter_context_acquire_id (self);
7192   priv->pick_id = -1;
7193
7194   priv->opacity = 0xff;
7195   priv->show_on_set_parent = TRUE;
7196
7197   priv->needs_width_request = TRUE;
7198   priv->needs_height_request = TRUE;
7199   priv->needs_allocation = TRUE;
7200
7201   priv->cached_width_age = 1;
7202   priv->cached_height_age = 1;
7203
7204   priv->opacity_override = -1;
7205   priv->enable_model_view_transform = TRUE;
7206
7207   /* Initialize an empty paint volume to start with */
7208   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7209   priv->last_paint_volume_valid = TRUE;
7210
7211   priv->transform_valid = FALSE;
7212
7213   /* the default is to stretch the content, to match the
7214    * current behaviour of basically all actors. also, it's
7215    * the easiest thing to compute.
7216    */
7217   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7218   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7219   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7220 }
7221
7222 /**
7223  * clutter_actor_new:
7224  *
7225  * Creates a new #ClutterActor.
7226  *
7227  * A newly created actor has a floating reference, which will be sunk
7228  * when it is added to another actor.
7229  *
7230  * Return value: (transfer full): the newly created #ClutterActor
7231  *
7232  * Since: 1.10
7233  */
7234 ClutterActor *
7235 clutter_actor_new (void)
7236 {
7237   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7238 }
7239
7240 /**
7241  * clutter_actor_destroy:
7242  * @self: a #ClutterActor
7243  *
7244  * Destroys an actor.  When an actor is destroyed, it will break any
7245  * references it holds to other objects.  If the actor is inside a
7246  * container, the actor will be removed.
7247  *
7248  * When you destroy a container, its children will be destroyed as well.
7249  *
7250  * Note: you cannot destroy the #ClutterStage returned by
7251  * clutter_stage_get_default().
7252  */
7253 void
7254 clutter_actor_destroy (ClutterActor *self)
7255 {
7256   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7257
7258   g_object_ref (self);
7259
7260   /* avoid recursion while destroying */
7261   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7262     {
7263       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7264
7265       g_object_run_dispose (G_OBJECT (self));
7266
7267       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7268     }
7269
7270   g_object_unref (self);
7271 }
7272
7273 void
7274 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7275                                     ClutterPaintVolume *clip)
7276 {
7277   ClutterActorPrivate *priv = self->priv;
7278   ClutterPaintVolume *pv;
7279   gboolean clipped;
7280
7281   /* Remove queue entry early in the process, otherwise a new
7282      queue_redraw() during signal handling could put back this
7283      object in the stage redraw list (but the entry is freed as
7284      soon as we return from this function, causing a segfault
7285      later)
7286   */
7287   priv->queue_redraw_entry = NULL;
7288
7289   /* If we've been explicitly passed a clip volume then there's
7290    * nothing more to calculate, but otherwise the only thing we know
7291    * is that the change is constrained to the given actor.
7292    *
7293    * The idea is that if we know the paint volume for where the actor
7294    * was last drawn (in eye coordinates) and we also have the paint
7295    * volume for where it will be drawn next (in actor coordinates)
7296    * then if we queue a redraw for both these volumes that will cover
7297    * everything that needs to be redrawn to clear the old view and
7298    * show the latest view of the actor.
7299    *
7300    * Don't clip this redraw if we don't know what position we had for
7301    * the previous redraw since we don't know where to set the clip so
7302    * it will clear the actor as it is currently.
7303    */
7304   if (clip)
7305     {
7306       _clutter_actor_set_queue_redraw_clip (self, clip);
7307       clipped = TRUE;
7308     }
7309   else if (G_LIKELY (priv->last_paint_volume_valid))
7310     {
7311       pv = _clutter_actor_get_paint_volume_mutable (self);
7312       if (pv)
7313         {
7314           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7315
7316           /* make sure we redraw the actors old position... */
7317           _clutter_actor_set_queue_redraw_clip (stage,
7318                                                 &priv->last_paint_volume);
7319           _clutter_actor_signal_queue_redraw (stage, stage);
7320           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7321
7322           /* XXX: Ideally the redraw signal would take a clip volume
7323            * argument, but that would be an ABI break. Until we can
7324            * break the ABI we pass the argument out-of-band
7325            */
7326
7327           /* setup the clip for the actors new position... */
7328           _clutter_actor_set_queue_redraw_clip (self, pv);
7329           clipped = TRUE;
7330         }
7331       else
7332         clipped = FALSE;
7333     }
7334   else
7335     clipped = FALSE;
7336
7337   _clutter_actor_signal_queue_redraw (self, self);
7338
7339   /* Just in case anyone is manually firing redraw signals without
7340    * using the public queue_redraw() API we are careful to ensure that
7341    * our out-of-band clip member is cleared before returning...
7342    *
7343    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7344    */
7345   if (G_LIKELY (clipped))
7346     _clutter_actor_set_queue_redraw_clip (self, NULL);
7347 }
7348
7349 static void
7350 _clutter_actor_get_allocation_clip (ClutterActor *self,
7351                                     ClutterActorBox *clip)
7352 {
7353   ClutterActorBox allocation;
7354
7355   /* XXX: we don't care if we get an out of date allocation here
7356    * because clutter_actor_queue_redraw_with_clip knows to ignore
7357    * the clip if the actor's allocation is invalid.
7358    *
7359    * This is noted because clutter_actor_get_allocation_box does some
7360    * unnecessary work to support buggy code with a comment suggesting
7361    * that it could be changed later which would be good for this use
7362    * case!
7363    */
7364   clutter_actor_get_allocation_box (self, &allocation);
7365
7366   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7367    * actor's own coordinate space but the allocation is in parent
7368    * coordinates */
7369   clip->x1 = 0;
7370   clip->y1 = 0;
7371   clip->x2 = allocation.x2 - allocation.x1;
7372   clip->y2 = allocation.y2 - allocation.y1;
7373 }
7374
7375 void
7376 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7377                                   ClutterRedrawFlags  flags,
7378                                   ClutterPaintVolume *volume,
7379                                   ClutterEffect      *effect)
7380 {
7381   ClutterActorPrivate *priv = self->priv;
7382   ClutterPaintVolume allocation_pv;
7383   ClutterPaintVolume *pv;
7384   gboolean should_free_pv;
7385   ClutterActor *stage;
7386
7387   /* Here's an outline of the actor queue redraw mechanism:
7388    *
7389    * The process starts in one of the following two functions which
7390    * are wrappers for this function:
7391    * clutter_actor_queue_redraw
7392    * _clutter_actor_queue_redraw_with_clip
7393    *
7394    * additionally, an effect can queue a redraw by wrapping this
7395    * function in clutter_effect_queue_rerun
7396    *
7397    * This functions queues an entry in a list associated with the
7398    * stage which is a list of actors that queued a redraw while
7399    * updating the timelines, performing layouting and processing other
7400    * mainloop sources before the next paint starts.
7401    *
7402    * We aim to minimize the processing done at this point because
7403    * there is a good chance other events will happen while updating
7404    * the scenegraph that would invalidate any expensive work we might
7405    * otherwise try to do here. For example we don't try and resolve
7406    * the screen space bounding box of an actor at this stage so as to
7407    * minimize how much of the screen redraw because it's possible
7408    * something else will happen which will force a full redraw anyway.
7409    *
7410    * When all updates are complete and we come to paint the stage then
7411    * we iterate this list and actually emit the "queue-redraw" signals
7412    * for each of the listed actors which will bubble up to the stage
7413    * for each actor and at that point we will transform the actors
7414    * paint volume into screen coordinates to determine the clip region
7415    * for what needs to be redrawn in the next paint.
7416    *
7417    * Besides minimizing redundant work another reason for this
7418    * deferred design is that it's more likely we will be able to
7419    * determine the paint volume of an actor once we've finished
7420    * updating the scenegraph because its allocation should be up to
7421    * date. NB: If we can't determine an actors paint volume then we
7422    * can't automatically queue a clipped redraw which can make a big
7423    * difference to performance.
7424    *
7425    * So the control flow goes like this:
7426    * One of clutter_actor_queue_redraw,
7427    *        _clutter_actor_queue_redraw_with_clip
7428    *     or clutter_effect_queue_rerun
7429    *
7430    * then control moves to:
7431    *   _clutter_stage_queue_actor_redraw
7432    *
7433    * later during _clutter_stage_do_update, once relayouting is done
7434    * and the scenegraph has been updated we will call:
7435    * _clutter_stage_finish_queue_redraws
7436    *
7437    * _clutter_stage_finish_queue_redraws will call
7438    * _clutter_actor_finish_queue_redraw for each listed actor.
7439    * Note: actors *are* allowed to queue further redraws during this
7440    * process (considering clone actors or texture_new_from_actor which
7441    * respond to their source queueing a redraw by queuing a redraw
7442    * themselves). We repeat the process until the list is empty.
7443    *
7444    * This will result in the "queue-redraw" signal being fired for
7445    * each actor which will pass control to the default signal handler:
7446    * clutter_actor_real_queue_redraw
7447    *
7448    * This will bubble up to the stages handler:
7449    * clutter_stage_real_queue_redraw
7450    *
7451    * clutter_stage_real_queue_redraw will transform the actors paint
7452    * volume into screen space and add it as a clip region for the next
7453    * paint.
7454    */
7455
7456   /* ignore queueing a redraw for actors being destroyed */
7457   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7458     return;
7459
7460   stage = _clutter_actor_get_stage_internal (self);
7461
7462   /* Ignore queueing a redraw for actors not descended from a stage */
7463   if (stage == NULL)
7464     return;
7465
7466   /* ignore queueing a redraw on stages that are being destroyed */
7467   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7468     return;
7469
7470   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7471     {
7472       ClutterActorBox allocation_clip;
7473       ClutterVertex origin;
7474
7475       /* If the actor doesn't have a valid allocation then we will
7476        * queue a full stage redraw. */
7477       if (priv->needs_allocation)
7478         {
7479           /* NB: NULL denotes an undefined clip which will result in a
7480            * full redraw... */
7481           _clutter_actor_set_queue_redraw_clip (self, NULL);
7482           _clutter_actor_signal_queue_redraw (self, self);
7483           return;
7484         }
7485
7486       _clutter_paint_volume_init_static (&allocation_pv, self);
7487       pv = &allocation_pv;
7488
7489       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7490
7491       origin.x = allocation_clip.x1;
7492       origin.y = allocation_clip.y1;
7493       origin.z = 0;
7494       clutter_paint_volume_set_origin (pv, &origin);
7495       clutter_paint_volume_set_width (pv,
7496                                       allocation_clip.x2 - allocation_clip.x1);
7497       clutter_paint_volume_set_height (pv,
7498                                        allocation_clip.y2 -
7499                                        allocation_clip.y1);
7500       should_free_pv = TRUE;
7501     }
7502   else
7503     {
7504       pv = volume;
7505       should_free_pv = FALSE;
7506     }
7507
7508   self->priv->queue_redraw_entry =
7509     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7510                                        priv->queue_redraw_entry,
7511                                        self,
7512                                        pv);
7513
7514   if (should_free_pv)
7515     clutter_paint_volume_free (pv);
7516
7517   /* If this is the first redraw queued then we can directly use the
7518      effect parameter */
7519   if (!priv->is_dirty)
7520     priv->effect_to_redraw = effect;
7521   /* Otherwise we need to merge it with the existing effect parameter */
7522   else if (effect != NULL)
7523     {
7524       /* If there's already an effect then we need to use whichever is
7525          later in the chain of actors. Otherwise a full redraw has
7526          already been queued on the actor so we need to ignore the
7527          effect parameter */
7528       if (priv->effect_to_redraw != NULL)
7529         {
7530           if (priv->effects == NULL)
7531             g_warning ("Redraw queued with an effect that is "
7532                        "not applied to the actor");
7533           else
7534             {
7535               const GList *l;
7536
7537               for (l = _clutter_meta_group_peek_metas (priv->effects);
7538                    l != NULL;
7539                    l = l->next)
7540                 {
7541                   if (l->data == priv->effect_to_redraw ||
7542                       l->data == effect)
7543                     priv->effect_to_redraw = l->data;
7544                 }
7545             }
7546         }
7547     }
7548   else
7549     {
7550       /* If no effect is specified then we need to redraw the whole
7551          actor */
7552       priv->effect_to_redraw = NULL;
7553     }
7554
7555   priv->is_dirty = TRUE;
7556 }
7557
7558 /**
7559  * clutter_actor_queue_redraw:
7560  * @self: A #ClutterActor
7561  *
7562  * Queues up a redraw of an actor and any children. The redraw occurs
7563  * once the main loop becomes idle (after the current batch of events
7564  * has been processed, roughly).
7565  *
7566  * Applications rarely need to call this, as redraws are handled
7567  * automatically by modification functions.
7568  *
7569  * This function will not do anything if @self is not visible, or
7570  * if the actor is inside an invisible part of the scenegraph.
7571  *
7572  * Also be aware that painting is a NOP for actors with an opacity of
7573  * 0
7574  *
7575  * When you are implementing a custom actor you must queue a redraw
7576  * whenever some private state changes that will affect painting or
7577  * picking of your actor.
7578  */
7579 void
7580 clutter_actor_queue_redraw (ClutterActor *self)
7581 {
7582   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7583
7584   _clutter_actor_queue_redraw_full (self,
7585                                     0, /* flags */
7586                                     NULL, /* clip volume */
7587                                     NULL /* effect */);
7588 }
7589
7590 /*< private >
7591  * _clutter_actor_queue_redraw_with_clip:
7592  * @self: A #ClutterActor
7593  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7594  *   this queue redraw.
7595  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7596  *   redrawn or %NULL if you are just using a @flag to state your
7597  *   desired clipping.
7598  *
7599  * Queues up a clipped redraw of an actor and any children. The redraw
7600  * occurs once the main loop becomes idle (after the current batch of
7601  * events has been processed, roughly).
7602  *
7603  * If no flags are given the clip volume is defined by @volume
7604  * specified in actor coordinates and tells Clutter that only content
7605  * within this volume has been changed so Clutter can optionally
7606  * optimize the redraw.
7607  *
7608  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7609  * should be %NULL and this tells Clutter to use the actor's current
7610  * allocation as a clip box. This flag can only be used for 2D actors,
7611  * because any actor with depth may be projected outside its
7612  * allocation.
7613  *
7614  * Applications rarely need to call this, as redraws are handled
7615  * automatically by modification functions.
7616  *
7617  * This function will not do anything if @self is not visible, or if
7618  * the actor is inside an invisible part of the scenegraph.
7619  *
7620  * Also be aware that painting is a NOP for actors with an opacity of
7621  * 0
7622  *
7623  * When you are implementing a custom actor you must queue a redraw
7624  * whenever some private state changes that will affect painting or
7625  * picking of your actor.
7626  */
7627 void
7628 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7629                                        ClutterRedrawFlags  flags,
7630                                        ClutterPaintVolume *volume)
7631 {
7632   _clutter_actor_queue_redraw_full (self,
7633                                     flags, /* flags */
7634                                     volume, /* clip volume */
7635                                     NULL /* effect */);
7636 }
7637
7638 static void
7639 _clutter_actor_queue_only_relayout (ClutterActor *self)
7640 {
7641   ClutterActorPrivate *priv = self->priv;
7642
7643   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7644     return;
7645
7646   if (priv->needs_width_request &&
7647       priv->needs_height_request &&
7648       priv->needs_allocation)
7649     return; /* save some cpu cycles */
7650
7651 #if CLUTTER_ENABLE_DEBUG
7652   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7653     {
7654       g_warning ("The actor '%s' is currently inside an allocation "
7655                  "cycle; calling clutter_actor_queue_relayout() is "
7656                  "not recommended",
7657                  _clutter_actor_get_debug_name (self));
7658     }
7659 #endif /* CLUTTER_ENABLE_DEBUG */
7660
7661   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7662 }
7663
7664 /**
7665  * clutter_actor_queue_redraw_with_clip:
7666  * @self: a #ClutterActor
7667  * @clip: (allow-none): a rectangular clip region, or %NULL
7668  *
7669  * Queues a redraw on @self limited to a specific, actor-relative
7670  * rectangular area.
7671  *
7672  * If @clip is %NULL this function is equivalent to
7673  * clutter_actor_queue_redraw().
7674  *
7675  * Since: 1.10
7676  */
7677 void
7678 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7679                                       const cairo_rectangle_int_t *clip)
7680 {
7681   ClutterPaintVolume volume;
7682   ClutterVertex origin;
7683
7684   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7685
7686   if (clip == NULL)
7687     {
7688       clutter_actor_queue_redraw (self);
7689       return;
7690     }
7691
7692   _clutter_paint_volume_init_static (&volume, self);
7693
7694   origin.x = clip->x;
7695   origin.y = clip->y;
7696   origin.z = 0.0f;
7697
7698   clutter_paint_volume_set_origin (&volume, &origin);
7699   clutter_paint_volume_set_width (&volume, clip->width);
7700   clutter_paint_volume_set_height (&volume, clip->height);
7701
7702   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7703
7704   clutter_paint_volume_free (&volume);
7705 }
7706
7707 /**
7708  * clutter_actor_queue_relayout:
7709  * @self: A #ClutterActor
7710  *
7711  * Indicates that the actor's size request or other layout-affecting
7712  * properties may have changed. This function is used inside #ClutterActor
7713  * subclass implementations, not by applications directly.
7714  *
7715  * Queueing a new layout automatically queues a redraw as well.
7716  *
7717  * Since: 0.8
7718  */
7719 void
7720 clutter_actor_queue_relayout (ClutterActor *self)
7721 {
7722   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7723
7724   _clutter_actor_queue_only_relayout (self);
7725   clutter_actor_queue_redraw (self);
7726 }
7727
7728 /**
7729  * clutter_actor_get_preferred_size:
7730  * @self: a #ClutterActor
7731  * @min_width_p: (out) (allow-none): return location for the minimum
7732  *   width, or %NULL
7733  * @min_height_p: (out) (allow-none): return location for the minimum
7734  *   height, or %NULL
7735  * @natural_width_p: (out) (allow-none): return location for the natural
7736  *   width, or %NULL
7737  * @natural_height_p: (out) (allow-none): return location for the natural
7738  *   height, or %NULL
7739  *
7740  * Computes the preferred minimum and natural size of an actor, taking into
7741  * account the actor's geometry management (either height-for-width
7742  * or width-for-height).
7743  *
7744  * The width and height used to compute the preferred height and preferred
7745  * width are the actor's natural ones.
7746  *
7747  * If you need to control the height for the preferred width, or the width for
7748  * the preferred height, you should use clutter_actor_get_preferred_width()
7749  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7750  * geometry management using the #ClutterActor:request-mode property.
7751  *
7752  * Since: 0.8
7753  */
7754 void
7755 clutter_actor_get_preferred_size (ClutterActor *self,
7756                                   gfloat       *min_width_p,
7757                                   gfloat       *min_height_p,
7758                                   gfloat       *natural_width_p,
7759                                   gfloat       *natural_height_p)
7760 {
7761   ClutterActorPrivate *priv;
7762   gfloat min_width, min_height;
7763   gfloat natural_width, natural_height;
7764
7765   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7766
7767   priv = self->priv;
7768
7769   min_width = min_height = 0;
7770   natural_width = natural_height = 0;
7771
7772   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7773     {
7774       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7775       clutter_actor_get_preferred_width (self, -1,
7776                                          &min_width,
7777                                          &natural_width);
7778       clutter_actor_get_preferred_height (self, natural_width,
7779                                           &min_height,
7780                                           &natural_height);
7781     }
7782   else
7783     {
7784       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7785       clutter_actor_get_preferred_height (self, -1,
7786                                           &min_height,
7787                                           &natural_height);
7788       clutter_actor_get_preferred_width (self, natural_height,
7789                                          &min_width,
7790                                          &natural_width);
7791     }
7792
7793   if (min_width_p)
7794     *min_width_p = min_width;
7795
7796   if (min_height_p)
7797     *min_height_p = min_height;
7798
7799   if (natural_width_p)
7800     *natural_width_p = natural_width;
7801
7802   if (natural_height_p)
7803     *natural_height_p = natural_height;
7804 }
7805
7806 /*< private >
7807  * effective_align:
7808  * @align: a #ClutterActorAlign
7809  * @direction: a #ClutterTextDirection
7810  *
7811  * Retrieves the correct alignment depending on the text direction
7812  *
7813  * Return value: the effective alignment
7814  */
7815 static ClutterActorAlign
7816 effective_align (ClutterActorAlign    align,
7817                  ClutterTextDirection direction)
7818 {
7819   ClutterActorAlign res;
7820
7821   switch (align)
7822     {
7823     case CLUTTER_ACTOR_ALIGN_START:
7824       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7825           ? CLUTTER_ACTOR_ALIGN_END
7826           : CLUTTER_ACTOR_ALIGN_START;
7827       break;
7828
7829     case CLUTTER_ACTOR_ALIGN_END:
7830       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7831           ? CLUTTER_ACTOR_ALIGN_START
7832           : CLUTTER_ACTOR_ALIGN_END;
7833       break;
7834
7835     default:
7836       res = align;
7837       break;
7838     }
7839
7840   return res;
7841 }
7842
7843 static inline void
7844 adjust_for_margin (float  margin_start,
7845                    float  margin_end,
7846                    float *minimum_size,
7847                    float *natural_size,
7848                    float *allocated_start,
7849                    float *allocated_end)
7850 {
7851   *minimum_size -= (margin_start + margin_end);
7852   *natural_size -= (margin_start + margin_end);
7853   *allocated_start += margin_start;
7854   *allocated_end -= margin_end;
7855 }
7856
7857 static inline void
7858 adjust_for_alignment (ClutterActorAlign  alignment,
7859                       float              natural_size,
7860                       float             *allocated_start,
7861                       float             *allocated_end)
7862 {
7863   float allocated_size = *allocated_end - *allocated_start;
7864
7865   switch (alignment)
7866     {
7867     case CLUTTER_ACTOR_ALIGN_FILL:
7868       /* do nothing */
7869       break;
7870
7871     case CLUTTER_ACTOR_ALIGN_START:
7872       /* keep start */
7873       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7874       break;
7875
7876     case CLUTTER_ACTOR_ALIGN_END:
7877       if (allocated_size > natural_size)
7878         {
7879           *allocated_start += (allocated_size - natural_size);
7880           *allocated_end = *allocated_start + natural_size;
7881         }
7882       break;
7883
7884     case CLUTTER_ACTOR_ALIGN_CENTER:
7885       if (allocated_size > natural_size)
7886         {
7887           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7888           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7889         }
7890       break;
7891     }
7892 }
7893
7894 /*< private >
7895  * clutter_actor_adjust_width:
7896  * @self: a #ClutterActor
7897  * @minimum_width: (inout): the actor's preferred minimum width, which
7898  *   will be adjusted depending on the margin
7899  * @natural_width: (inout): the actor's preferred natural width, which
7900  *   will be adjusted depending on the margin
7901  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7902  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7903  *
7904  * Adjusts the preferred and allocated position and size of an actor,
7905  * depending on the margin and alignment properties.
7906  */
7907 static void
7908 clutter_actor_adjust_width (ClutterActor *self,
7909                             gfloat       *minimum_width,
7910                             gfloat       *natural_width,
7911                             gfloat       *adjusted_x1,
7912                             gfloat       *adjusted_x2)
7913 {
7914   ClutterTextDirection text_dir;
7915   const ClutterLayoutInfo *info;
7916
7917   info = _clutter_actor_get_layout_info_or_defaults (self);
7918   text_dir = clutter_actor_get_text_direction (self);
7919
7920   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7921
7922   /* this will tweak natural_width to remove the margin, so that
7923    * adjust_for_alignment() will use the correct size
7924    */
7925   adjust_for_margin (info->margin.left, info->margin.right,
7926                      minimum_width, natural_width,
7927                      adjusted_x1, adjusted_x2);
7928
7929   adjust_for_alignment (effective_align (info->x_align, text_dir),
7930                         *natural_width,
7931                         adjusted_x1, adjusted_x2);
7932 }
7933
7934 /*< private >
7935  * clutter_actor_adjust_height:
7936  * @self: a #ClutterActor
7937  * @minimum_height: (inout): the actor's preferred minimum height, which
7938  *   will be adjusted depending on the margin
7939  * @natural_height: (inout): the actor's preferred natural height, which
7940  *   will be adjusted depending on the margin
7941  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7942  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7943  *
7944  * Adjusts the preferred and allocated position and size of an actor,
7945  * depending on the margin and alignment properties.
7946  */
7947 static void
7948 clutter_actor_adjust_height (ClutterActor *self,
7949                              gfloat       *minimum_height,
7950                              gfloat       *natural_height,
7951                              gfloat       *adjusted_y1,
7952                              gfloat       *adjusted_y2)
7953 {
7954   const ClutterLayoutInfo *info;
7955
7956   info = _clutter_actor_get_layout_info_or_defaults (self);
7957
7958   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7959
7960   /* this will tweak natural_height to remove the margin, so that
7961    * adjust_for_alignment() will use the correct size
7962    */
7963   adjust_for_margin (info->margin.top, info->margin.bottom,
7964                      minimum_height, natural_height,
7965                      adjusted_y1,
7966                      adjusted_y2);
7967
7968   /* we don't use effective_align() here, because text direction
7969    * only affects the horizontal axis
7970    */
7971   adjust_for_alignment (info->y_align,
7972                         *natural_height,
7973                         adjusted_y1,
7974                         adjusted_y2);
7975
7976 }
7977
7978 /* looks for a cached size request for this for_size. If not
7979  * found, returns the oldest entry so it can be overwritten */
7980 static gboolean
7981 _clutter_actor_get_cached_size_request (gfloat         for_size,
7982                                         SizeRequest   *cached_size_requests,
7983                                         SizeRequest  **result)
7984 {
7985   guint i;
7986
7987   *result = &cached_size_requests[0];
7988
7989   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7990     {
7991       SizeRequest *sr;
7992
7993       sr = &cached_size_requests[i];
7994
7995       if (sr->age > 0 &&
7996           sr->for_size == for_size)
7997         {
7998           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7999           *result = sr;
8000           return TRUE;
8001         }
8002       else if (sr->age < (*result)->age)
8003         {
8004           *result = sr;
8005         }
8006     }
8007
8008   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
8009
8010   return FALSE;
8011 }
8012
8013 /**
8014  * clutter_actor_get_preferred_width:
8015  * @self: A #ClutterActor
8016  * @for_height: available height when computing the preferred width,
8017  *   or a negative value to indicate that no height is defined
8018  * @min_width_p: (out) (allow-none): return location for minimum width,
8019  *   or %NULL
8020  * @natural_width_p: (out) (allow-none): return location for the natural
8021  *   width, or %NULL
8022  *
8023  * Computes the requested minimum and natural widths for an actor,
8024  * optionally depending on the specified height, or if they are
8025  * already computed, returns the cached values.
8026  *
8027  * An actor may not get its request - depending on the layout
8028  * manager that's in effect.
8029  *
8030  * A request should not incorporate the actor's scale or anchor point;
8031  * those transformations do not affect layout, only rendering.
8032  *
8033  * Since: 0.8
8034  */
8035 void
8036 clutter_actor_get_preferred_width (ClutterActor *self,
8037                                    gfloat        for_height,
8038                                    gfloat       *min_width_p,
8039                                    gfloat       *natural_width_p)
8040 {
8041   float request_min_width, request_natural_width;
8042   SizeRequest *cached_size_request;
8043   const ClutterLayoutInfo *info;
8044   ClutterActorPrivate *priv;
8045   gboolean found_in_cache;
8046
8047   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8048
8049   priv = self->priv;
8050
8051   info = _clutter_actor_get_layout_info_or_defaults (self);
8052
8053   /* we shortcircuit the case of a fixed size set using set_width() */
8054   if (priv->min_width_set && priv->natural_width_set)
8055     {
8056       if (min_width_p != NULL)
8057         *min_width_p = info->minimum.width + (info->margin.left + info->margin.right);
8058
8059       if (natural_width_p != NULL)
8060         *natural_width_p = info->natural.width + (info->margin.left + info->margin.right);
8061
8062       return;
8063     }
8064
8065   /* the remaining cases are:
8066    *
8067    *   - either min_width or natural_width have been set
8068    *   - neither min_width or natural_width have been set
8069    *
8070    * in both cases, we go through the cache (and through the actor in case
8071    * of cache misses) and determine the authoritative value depending on
8072    * the *_set flags.
8073    */
8074
8075   if (!priv->needs_width_request)
8076     {
8077       found_in_cache =
8078         _clutter_actor_get_cached_size_request (for_height,
8079                                                 priv->width_requests,
8080                                                 &cached_size_request);
8081     }
8082   else
8083     {
8084       /* if the actor needs a width request we use the first slot */
8085       found_in_cache = FALSE;
8086       cached_size_request = &priv->width_requests[0];
8087     }
8088
8089   if (!found_in_cache)
8090     {
8091       gfloat minimum_width, natural_width;
8092       ClutterActorClass *klass;
8093
8094       minimum_width = natural_width = 0;
8095
8096       /* adjust for the margin */
8097       if (for_height >= 0)
8098         {
8099           for_height -= (info->margin.top + info->margin.bottom);
8100           if (for_height < 0)
8101             for_height = 0;
8102         }
8103
8104       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
8105
8106       klass = CLUTTER_ACTOR_GET_CLASS (self);
8107       klass->get_preferred_width (self, for_height,
8108                                   &minimum_width,
8109                                   &natural_width);
8110
8111       /* adjust for the margin */
8112       minimum_width += (info->margin.left + info->margin.right);
8113       natural_width += (info->margin.left + info->margin.right);
8114
8115       /* Due to accumulated float errors, it's better not to warn
8116        * on this, but just fix it.
8117        */
8118       if (natural_width < minimum_width)
8119         natural_width = minimum_width;
8120
8121       cached_size_request->min_size = minimum_width;
8122       cached_size_request->natural_size = natural_width;
8123       cached_size_request->for_size = for_height;
8124       cached_size_request->age = priv->cached_width_age;
8125
8126       priv->cached_width_age += 1;
8127       priv->needs_width_request = FALSE;
8128     }
8129
8130   if (!priv->min_width_set)
8131     request_min_width = cached_size_request->min_size;
8132   else
8133     request_min_width = info->minimum.width;
8134
8135   if (!priv->natural_width_set)
8136     request_natural_width = cached_size_request->natural_size;
8137   else
8138     request_natural_width = info->natural.width;
8139
8140   if (min_width_p)
8141     *min_width_p = request_min_width;
8142
8143   if (natural_width_p)
8144     *natural_width_p = request_natural_width;
8145 }
8146
8147 /**
8148  * clutter_actor_get_preferred_height:
8149  * @self: A #ClutterActor
8150  * @for_width: available width to assume in computing desired height,
8151  *   or a negative value to indicate that no width is defined
8152  * @min_height_p: (out) (allow-none): return location for minimum height,
8153  *   or %NULL
8154  * @natural_height_p: (out) (allow-none): return location for natural
8155  *   height, or %NULL
8156  *
8157  * Computes the requested minimum and natural heights for an actor,
8158  * or if they are already computed, returns the cached values.
8159  *
8160  * An actor may not get its request - depending on the layout
8161  * manager that's in effect.
8162  *
8163  * A request should not incorporate the actor's scale or anchor point;
8164  * those transformations do not affect layout, only rendering.
8165  *
8166  * Since: 0.8
8167  */
8168 void
8169 clutter_actor_get_preferred_height (ClutterActor *self,
8170                                     gfloat        for_width,
8171                                     gfloat       *min_height_p,
8172                                     gfloat       *natural_height_p)
8173 {
8174   float request_min_height, request_natural_height;
8175   SizeRequest *cached_size_request;
8176   const ClutterLayoutInfo *info;
8177   ClutterActorPrivate *priv;
8178   gboolean found_in_cache;
8179
8180   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8181
8182   priv = self->priv;
8183
8184   info = _clutter_actor_get_layout_info_or_defaults (self);
8185
8186   /* we shortcircuit the case of a fixed size set using set_height() */
8187   if (priv->min_height_set && priv->natural_height_set)
8188     {
8189       if (min_height_p != NULL)
8190         *min_height_p = info->minimum.height + (info->margin.top + info->margin.bottom);
8191
8192       if (natural_height_p != NULL)
8193         *natural_height_p = info->natural.height + (info->margin.top + info->margin.bottom);
8194
8195       return;
8196     }
8197
8198   /* the remaining cases are:
8199    *
8200    *   - either min_height or natural_height have been set
8201    *   - neither min_height or natural_height have been set
8202    *
8203    * in both cases, we go through the cache (and through the actor in case
8204    * of cache misses) and determine the authoritative value depending on
8205    * the *_set flags.
8206    */
8207
8208   if (!priv->needs_height_request)
8209     {
8210       found_in_cache =
8211         _clutter_actor_get_cached_size_request (for_width,
8212                                                 priv->height_requests,
8213                                                 &cached_size_request);
8214     }
8215   else
8216     {
8217       found_in_cache = FALSE;
8218       cached_size_request = &priv->height_requests[0];
8219     }
8220
8221   if (!found_in_cache)
8222     {
8223       gfloat minimum_height, natural_height;
8224       ClutterActorClass *klass;
8225
8226       minimum_height = natural_height = 0;
8227
8228       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8229
8230       /* adjust for margin */
8231       if (for_width >= 0)
8232         {
8233           for_width -= (info->margin.left + info->margin.right);
8234           if (for_width < 0)
8235             for_width = 0;
8236         }
8237
8238       klass = CLUTTER_ACTOR_GET_CLASS (self);
8239       klass->get_preferred_height (self, for_width,
8240                                    &minimum_height,
8241                                    &natural_height);
8242
8243       /* adjust for margin */
8244       minimum_height += (info->margin.top + info->margin.bottom);
8245       natural_height += (info->margin.top + info->margin.bottom);
8246
8247       /* Due to accumulated float errors, it's better not to warn
8248        * on this, but just fix it.
8249        */
8250       if (natural_height < minimum_height)
8251         natural_height = minimum_height;
8252
8253       cached_size_request->min_size = minimum_height;
8254       cached_size_request->natural_size = natural_height;
8255       cached_size_request->for_size = for_width;
8256       cached_size_request->age = priv->cached_height_age;
8257
8258       priv->cached_height_age += 1;
8259       priv->needs_height_request = FALSE;
8260     }
8261
8262   if (!priv->min_height_set)
8263     request_min_height = cached_size_request->min_size;
8264   else
8265     request_min_height = info->minimum.height;
8266
8267   if (!priv->natural_height_set)
8268     request_natural_height = cached_size_request->natural_size;
8269   else
8270     request_natural_height = info->natural.height;
8271
8272   if (min_height_p)
8273     *min_height_p = request_min_height;
8274
8275   if (natural_height_p)
8276     *natural_height_p = request_natural_height;
8277 }
8278
8279 /**
8280  * clutter_actor_get_allocation_box:
8281  * @self: A #ClutterActor
8282  * @box: (out): the function fills this in with the actor's allocation
8283  *
8284  * Gets the layout box an actor has been assigned. The allocation can
8285  * only be assumed valid inside a paint() method; anywhere else, it
8286  * may be out-of-date.
8287  *
8288  * An allocation does not incorporate the actor's scale or anchor point;
8289  * those transformations do not affect layout, only rendering.
8290  *
8291  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8292  * of functions inside the implementation of the get_preferred_width()
8293  * or get_preferred_height() virtual functions.</note>
8294  *
8295  * Since: 0.8
8296  */
8297 void
8298 clutter_actor_get_allocation_box (ClutterActor    *self,
8299                                   ClutterActorBox *box)
8300 {
8301   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8302
8303   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8304    * which limits calling get_allocation to inside paint() basically; or
8305    * we can 2) force a layout, which could be expensive if someone calls
8306    * get_allocation somewhere silly; or we can 3) just return the latest
8307    * value, allowing it to be out-of-date, and assume people know what
8308    * they are doing.
8309    *
8310    * The least-surprises approach that keeps existing code working is
8311    * likely to be 2). People can end up doing some inefficient things,
8312    * though, and in general code that requires 2) is probably broken.
8313    */
8314
8315   /* this implements 2) */
8316   if (G_UNLIKELY (self->priv->needs_allocation))
8317     {
8318       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8319
8320       /* do not queue a relayout on an unparented actor */
8321       if (stage)
8322         _clutter_stage_maybe_relayout (stage);
8323     }
8324
8325   /* commenting out the code above and just keeping this assigment
8326    * implements 3)
8327    */
8328   *box = self->priv->allocation;
8329 }
8330
8331 /**
8332  * clutter_actor_get_allocation_geometry:
8333  * @self: A #ClutterActor
8334  * @geom: (out): allocation geometry in pixels
8335  *
8336  * Gets the layout box an actor has been assigned.  The allocation can
8337  * only be assumed valid inside a paint() method; anywhere else, it
8338  * may be out-of-date.
8339  *
8340  * An allocation does not incorporate the actor's scale or anchor point;
8341  * those transformations do not affect layout, only rendering.
8342  *
8343  * The returned rectangle is in pixels.
8344  *
8345  * Since: 0.8
8346  */
8347 void
8348 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8349                                        ClutterGeometry *geom)
8350 {
8351   ClutterActorBox box;
8352
8353   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8354   g_return_if_fail (geom != NULL);
8355
8356   clutter_actor_get_allocation_box (self, &box);
8357
8358   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8359   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8360   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8361   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8362 }
8363
8364 static void
8365 clutter_actor_update_constraints (ClutterActor    *self,
8366                                   ClutterActorBox *allocation)
8367 {
8368   ClutterActorPrivate *priv = self->priv;
8369   const GList *constraints, *l;
8370
8371   if (priv->constraints == NULL)
8372     return;
8373
8374   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8375   for (l = constraints; l != NULL; l = l->next)
8376     {
8377       ClutterConstraint *constraint = l->data;
8378       ClutterActorMeta *meta = l->data;
8379
8380       if (clutter_actor_meta_get_enabled (meta))
8381         {
8382           _clutter_constraint_update_allocation (constraint,
8383                                                  self,
8384                                                  allocation);
8385
8386           CLUTTER_NOTE (LAYOUT,
8387                         "Allocation of '%s' after constraint '%s': "
8388                         "{ %.2f, %.2f, %.2f, %.2f }",
8389                         _clutter_actor_get_debug_name (self),
8390                         _clutter_actor_meta_get_debug_name (meta),
8391                         allocation->x1,
8392                         allocation->y1,
8393                         allocation->x2,
8394                         allocation->y2);
8395         }
8396     }
8397 }
8398
8399 /*< private >
8400  * clutter_actor_adjust_allocation:
8401  * @self: a #ClutterActor
8402  * @allocation: (inout): the allocation to adjust
8403  *
8404  * Adjusts the passed allocation box taking into account the actor's
8405  * layout information, like alignment, expansion, and margin.
8406  */
8407 static void
8408 clutter_actor_adjust_allocation (ClutterActor    *self,
8409                                  ClutterActorBox *allocation)
8410 {
8411   ClutterActorBox adj_allocation;
8412   float alloc_width, alloc_height;
8413   float min_width, min_height;
8414   float nat_width, nat_height;
8415   ClutterRequestMode req_mode;
8416
8417   adj_allocation = *allocation;
8418
8419   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8420
8421   /* we want to hit the cache, so we use the public API */
8422   req_mode = clutter_actor_get_request_mode (self);
8423
8424   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8425     {
8426       clutter_actor_get_preferred_width (self, -1,
8427                                          &min_width,
8428                                          &nat_width);
8429       clutter_actor_get_preferred_height (self, alloc_width,
8430                                           &min_height,
8431                                           &nat_height);
8432     }
8433   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8434     {
8435       clutter_actor_get_preferred_height (self, -1,
8436                                           &min_height,
8437                                           &nat_height);
8438       clutter_actor_get_preferred_height (self, alloc_height,
8439                                           &min_width,
8440                                           &nat_width);
8441     }
8442
8443 #ifdef CLUTTER_ENABLE_DEBUG
8444   /* warn about underallocations */
8445   if (_clutter_diagnostic_enabled () &&
8446       (floorf (min_width - alloc_width) > 0 ||
8447        floorf (min_height - alloc_height) > 0))
8448     {
8449       ClutterActor *parent = clutter_actor_get_parent (self);
8450
8451       /* the only actors that are allowed to be underallocated are the Stage,
8452        * as it doesn't have an implicit size, and Actors that specifically
8453        * told us that they want to opt-out from layout control mechanisms
8454        * through the NO_LAYOUT escape hatch.
8455        */
8456       if (parent != NULL &&
8457           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8458         {
8459           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8460                      "of %.2f x %.2f from its parent actor '%s', but its "
8461                      "requested minimum size is of %.2f x %.2f",
8462                      _clutter_actor_get_debug_name (self),
8463                      alloc_width, alloc_height,
8464                      _clutter_actor_get_debug_name (parent),
8465                      min_width, min_height);
8466         }
8467     }
8468 #endif
8469
8470   clutter_actor_adjust_width (self,
8471                               &min_width,
8472                               &nat_width,
8473                               &adj_allocation.x1,
8474                               &adj_allocation.x2);
8475
8476   clutter_actor_adjust_height (self,
8477                                &min_height,
8478                                &nat_height,
8479                                &adj_allocation.y1,
8480                                &adj_allocation.y2);
8481
8482   /* we maintain the invariant that an allocation cannot be adjusted
8483    * to be outside the parent-given box
8484    */
8485   if (adj_allocation.x1 < allocation->x1 ||
8486       adj_allocation.y1 < allocation->y1 ||
8487       adj_allocation.x2 > allocation->x2 ||
8488       adj_allocation.y2 > allocation->y2)
8489     {
8490       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8491                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8492                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8493                  _clutter_actor_get_debug_name (self),
8494                  adj_allocation.x1, adj_allocation.y1,
8495                  adj_allocation.x2 - adj_allocation.x1,
8496                  adj_allocation.y2 - adj_allocation.y1,
8497                  allocation->x1, allocation->y1,
8498                  allocation->x2 - allocation->x1,
8499                  allocation->y2 - allocation->y1);
8500       return;
8501     }
8502
8503   *allocation = adj_allocation;
8504 }
8505
8506 /**
8507  * clutter_actor_allocate:
8508  * @self: A #ClutterActor
8509  * @box: new allocation of the actor, in parent-relative coordinates
8510  * @flags: flags that control the allocation
8511  *
8512  * Called by the parent of an actor to assign the actor its size.
8513  * Should never be called by applications (except when implementing
8514  * a container or layout manager).
8515  *
8516  * Actors can know from their allocation box whether they have moved
8517  * with respect to their parent actor. The @flags parameter describes
8518  * additional information about the allocation, for instance whether
8519  * the parent has moved with respect to the stage, for example because
8520  * a grandparent's origin has moved.
8521  *
8522  * Since: 0.8
8523  */
8524 void
8525 clutter_actor_allocate (ClutterActor           *self,
8526                         const ClutterActorBox  *box,
8527                         ClutterAllocationFlags  flags)
8528 {
8529   ClutterActorPrivate *priv;
8530   ClutterActorClass *klass;
8531   ClutterActorBox old_allocation, real_allocation;
8532   gboolean origin_changed, child_moved, size_changed;
8533   gboolean stage_allocation_changed;
8534
8535   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8536   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8537     {
8538       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8539                  "which isn't a descendent of the stage!\n",
8540                  self, _clutter_actor_get_debug_name (self));
8541       return;
8542     }
8543
8544   priv = self->priv;
8545
8546   old_allocation = priv->allocation;
8547   real_allocation = *box;
8548
8549   /* constraints are allowed to modify the allocation only here; we do
8550    * this prior to all the other checks so that we can bail out if the
8551    * allocation did not change
8552    */
8553   clutter_actor_update_constraints (self, &real_allocation);
8554
8555   /* adjust the allocation depending on the align/margin properties */
8556   clutter_actor_adjust_allocation (self, &real_allocation);
8557
8558   if (real_allocation.x2 < real_allocation.x1 ||
8559       real_allocation.y2 < real_allocation.y1)
8560     {
8561       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8562                  _clutter_actor_get_debug_name (self),
8563                  real_allocation.x2 - real_allocation.x1,
8564                  real_allocation.y2 - real_allocation.y1);
8565     }
8566
8567   /* we allow 0-sized actors, but not negative-sized ones */
8568   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8569   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8570
8571   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8572
8573   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8574                  real_allocation.y1 != old_allocation.y1);
8575
8576   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8577                   real_allocation.y2 != old_allocation.y2);
8578
8579   if (origin_changed || child_moved || size_changed)
8580     stage_allocation_changed = TRUE;
8581   else
8582     stage_allocation_changed = FALSE;
8583
8584   /* If we get an allocation "out of the blue"
8585    * (we did not queue relayout), then we want to
8586    * ignore it. But if we have needs_allocation set,
8587    * we want to guarantee that allocate() virtual
8588    * method is always called, i.e. that queue_relayout()
8589    * always results in an allocate() invocation on
8590    * an actor.
8591    *
8592    * The optimization here is to avoid re-allocating
8593    * actors that did not queue relayout and were
8594    * not moved.
8595    */
8596   if (!priv->needs_allocation && !stage_allocation_changed)
8597     {
8598       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8599       return;
8600     }
8601
8602   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8603    * clutter_actor_allocate(), it indicates whether the parent has its
8604    * absolute origin moved; when passed in to ClutterActor::allocate()
8605    * virtual method though, it indicates whether the child has its
8606    * absolute origin moved.  So we set it when child_moved is TRUE
8607    */
8608   if (child_moved)
8609     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8610
8611   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8612
8613   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8614                 _clutter_actor_get_debug_name (self));
8615
8616   klass = CLUTTER_ACTOR_GET_CLASS (self);
8617   klass->allocate (self, &real_allocation, flags);
8618
8619   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8620
8621   if (stage_allocation_changed)
8622     clutter_actor_queue_redraw (self);
8623 }
8624
8625 /**
8626  * clutter_actor_set_allocation:
8627  * @self: a #ClutterActor
8628  * @box: a #ClutterActorBox
8629  * @flags: allocation flags
8630  *
8631  * Stores the allocation of @self as defined by @box.
8632  *
8633  * This function can only be called from within the implementation of
8634  * the #ClutterActorClass.allocate() virtual function.
8635  *
8636  * The allocation should have been adjusted to take into account constraints,
8637  * alignment, and margin properties. If you are implementing a #ClutterActor
8638  * subclass that provides its own layout management policy for its children
8639  * instead of using a #ClutterLayoutManager delegate, you should not call
8640  * this function on the children of @self; instead, you should call
8641  * clutter_actor_allocate(), which will adjust the allocation box for
8642  * you.
8643  *
8644  * This function should only be used by subclasses of #ClutterActor
8645  * that wish to store their allocation but cannot chain up to the
8646  * parent's implementation; the default implementation of the
8647  * #ClutterActorClass.allocate() virtual function will call this
8648  * function.
8649  *
8650  * It is important to note that, while chaining up was the recommended
8651  * behaviour for #ClutterActor subclasses prior to the introduction of
8652  * this function, it is recommended to call clutter_actor_set_allocation()
8653  * instead.
8654  *
8655  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8656  * to handle the allocation of its children, this function will call
8657  * the clutter_layout_manager_allocate() function only if the
8658  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8659  * expected that the subclass will call clutter_layout_manager_allocate()
8660  * by itself. For instance, the following code:
8661  *
8662  * |[
8663  * static void
8664  * my_actor_allocate (ClutterActor *actor,
8665  *                    const ClutterActorBox *allocation,
8666  *                    ClutterAllocationFlags flags)
8667  * {
8668  *   ClutterActorBox new_alloc;
8669  *   ClutterAllocationFlags new_flags;
8670  *
8671  *   adjust_allocation (allocation, &amp;new_alloc);
8672  *
8673  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8674  *
8675  *   /&ast; this will use the layout manager set on the actor &ast;/
8676  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8677  * }
8678  * ]|
8679  *
8680  * is equivalent to this:
8681  *
8682  * |[
8683  * static void
8684  * my_actor_allocate (ClutterActor *actor,
8685  *                    const ClutterActorBox *allocation,
8686  *                    ClutterAllocationFlags flags)
8687  * {
8688  *   ClutterLayoutManager *layout;
8689  *   ClutterActorBox new_alloc;
8690  *
8691  *   adjust_allocation (allocation, &amp;new_alloc);
8692  *
8693  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8694  *
8695  *   layout = clutter_actor_get_layout_manager (actor);
8696  *   clutter_layout_manager_allocate (layout,
8697  *                                    CLUTTER_CONTAINER (actor),
8698  *                                    &amp;new_alloc,
8699  *                                    flags);
8700  * }
8701  * ]|
8702  *
8703  * Since: 1.10
8704  */
8705 void
8706 clutter_actor_set_allocation (ClutterActor           *self,
8707                               const ClutterActorBox  *box,
8708                               ClutterAllocationFlags  flags)
8709 {
8710   ClutterActorPrivate *priv;
8711   gboolean changed;
8712
8713   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8714   g_return_if_fail (box != NULL);
8715
8716   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8717     {
8718       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8719                   "can only be called from within the implementation of "
8720                   "the ClutterActor::allocate() virtual function.");
8721       return;
8722     }
8723
8724   priv = self->priv;
8725
8726   g_object_freeze_notify (G_OBJECT (self));
8727
8728   changed = clutter_actor_set_allocation_internal (self, box, flags);
8729
8730   /* we allocate our children before we notify changes in our geometry,
8731    * so that people connecting to properties will be able to get valid
8732    * data out of the sub-tree of the scene graph that has this actor at
8733    * the root.
8734    */
8735   clutter_actor_maybe_layout_children (self, box, flags);
8736
8737   if (changed)
8738     {
8739       ClutterActorBox signal_box = priv->allocation;
8740       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8741
8742       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8743                      &signal_box,
8744                      signal_flags);
8745     }
8746
8747   g_object_thaw_notify (G_OBJECT (self));
8748 }
8749
8750 /**
8751  * clutter_actor_set_geometry:
8752  * @self: A #ClutterActor
8753  * @geometry: A #ClutterGeometry
8754  *
8755  * Sets the actor's fixed position and forces its minimum and natural
8756  * size, in pixels. This means the untransformed actor will have the
8757  * given geometry. This is the same as calling clutter_actor_set_position()
8758  * and clutter_actor_set_size().
8759  *
8760  * Deprecated: 1.10: Use clutter_actor_set_position() and
8761  *   clutter_actor_set_size() instead.
8762  */
8763 void
8764 clutter_actor_set_geometry (ClutterActor          *self,
8765                             const ClutterGeometry *geometry)
8766 {
8767   g_object_freeze_notify (G_OBJECT (self));
8768
8769   clutter_actor_set_position (self, geometry->x, geometry->y);
8770   clutter_actor_set_size (self, geometry->width, geometry->height);
8771
8772   g_object_thaw_notify (G_OBJECT (self));
8773 }
8774
8775 /**
8776  * clutter_actor_get_geometry:
8777  * @self: A #ClutterActor
8778  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8779  *
8780  * Gets the size and position of an actor relative to its parent
8781  * actor. This is the same as calling clutter_actor_get_position() and
8782  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8783  * requested size and position if the actor's allocation is invalid.
8784  *
8785  * Deprecated: 1.10: Use clutter_actor_get_position() and
8786  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8787  *   instead.
8788  */
8789 void
8790 clutter_actor_get_geometry (ClutterActor    *self,
8791                             ClutterGeometry *geometry)
8792 {
8793   gfloat x, y, width, height;
8794
8795   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8796   g_return_if_fail (geometry != NULL);
8797
8798   clutter_actor_get_position (self, &x, &y);
8799   clutter_actor_get_size (self, &width, &height);
8800
8801   geometry->x = (int) x;
8802   geometry->y = (int) y;
8803   geometry->width = (int) width;
8804   geometry->height = (int) height;
8805 }
8806
8807 /**
8808  * clutter_actor_set_position:
8809  * @self: A #ClutterActor
8810  * @x: New left position of actor in pixels.
8811  * @y: New top position of actor in pixels.
8812  *
8813  * Sets the actor's fixed position in pixels relative to any parent
8814  * actor.
8815  *
8816  * If a layout manager is in use, this position will override the
8817  * layout manager and force a fixed position.
8818  */
8819 void
8820 clutter_actor_set_position (ClutterActor *self,
8821                             gfloat        x,
8822                             gfloat        y)
8823 {
8824   ClutterPoint new_position;
8825
8826   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8827
8828   clutter_point_init (&new_position, x, y);
8829
8830   if (_clutter_actor_get_transition (self, obj_props[PROP_POSITION]) == NULL)
8831     {
8832       ClutterPoint cur_position;
8833
8834       cur_position.x = clutter_actor_get_x (self);
8835       cur_position.y = clutter_actor_get_y (self);
8836
8837       _clutter_actor_create_transition (self, obj_props[PROP_POSITION],
8838                                         &cur_position,
8839                                         &new_position);
8840     }
8841   else
8842     _clutter_actor_update_transition (self,
8843                                       obj_props[PROP_POSITION],
8844                                       &new_position);
8845
8846   clutter_actor_queue_relayout (self);
8847 }
8848
8849 /**
8850  * clutter_actor_get_fixed_position_set:
8851  * @self: A #ClutterActor
8852  *
8853  * Checks whether an actor has a fixed position set (and will thus be
8854  * unaffected by any layout manager).
8855  *
8856  * Return value: %TRUE if the fixed position is set on the actor
8857  *
8858  * Since: 0.8
8859  */
8860 gboolean
8861 clutter_actor_get_fixed_position_set (ClutterActor *self)
8862 {
8863   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8864
8865   return self->priv->position_set;
8866 }
8867
8868 /**
8869  * clutter_actor_set_fixed_position_set:
8870  * @self: A #ClutterActor
8871  * @is_set: whether to use fixed position
8872  *
8873  * Sets whether an actor has a fixed position set (and will thus be
8874  * unaffected by any layout manager).
8875  *
8876  * Since: 0.8
8877  */
8878 void
8879 clutter_actor_set_fixed_position_set (ClutterActor *self,
8880                                       gboolean      is_set)
8881 {
8882   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8883
8884   if (self->priv->position_set == (is_set != FALSE))
8885     return;
8886
8887   self->priv->position_set = is_set != FALSE;
8888   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8889
8890   clutter_actor_queue_relayout (self);
8891 }
8892
8893 /**
8894  * clutter_actor_move_by:
8895  * @self: A #ClutterActor
8896  * @dx: Distance to move Actor on X axis.
8897  * @dy: Distance to move Actor on Y axis.
8898  *
8899  * Moves an actor by the specified distance relative to its current
8900  * position in pixels.
8901  *
8902  * This function modifies the fixed position of an actor and thus removes
8903  * it from any layout management. Another way to move an actor is with an
8904  * anchor point, see clutter_actor_set_anchor_point().
8905  *
8906  * Since: 0.2
8907  */
8908 void
8909 clutter_actor_move_by (ClutterActor *self,
8910                        gfloat        dx,
8911                        gfloat        dy)
8912 {
8913   const ClutterLayoutInfo *info;
8914   gfloat x, y;
8915
8916   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8917
8918   info = _clutter_actor_get_layout_info_or_defaults (self);
8919   x = info->fixed_pos.x;
8920   y = info->fixed_pos.y;
8921
8922   clutter_actor_set_position (self, x + dx, y + dy);
8923 }
8924
8925 static void
8926 clutter_actor_set_min_width (ClutterActor *self,
8927                              gfloat        min_width)
8928 {
8929   ClutterActorPrivate *priv = self->priv;
8930   ClutterActorBox old = { 0, };
8931   ClutterLayoutInfo *info;
8932
8933   /* if we are setting the size on a top-level actor and the
8934    * backend only supports static top-levels (e.g. framebuffers)
8935    * then we ignore the passed value and we override it with
8936    * the stage implementation's preferred size.
8937    */
8938   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8939       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8940     return;
8941
8942   info = _clutter_actor_get_layout_info (self);
8943
8944   if (priv->min_width_set && min_width == info->minimum.width)
8945     return;
8946
8947   g_object_freeze_notify (G_OBJECT (self));
8948
8949   clutter_actor_store_old_geometry (self, &old);
8950
8951   info->minimum.width = min_width;
8952   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8953   clutter_actor_set_min_width_set (self, TRUE);
8954
8955   clutter_actor_notify_if_geometry_changed (self, &old);
8956
8957   g_object_thaw_notify (G_OBJECT (self));
8958
8959   clutter_actor_queue_relayout (self);
8960 }
8961
8962 static void
8963 clutter_actor_set_min_height (ClutterActor *self,
8964                               gfloat        min_height)
8965
8966 {
8967   ClutterActorPrivate *priv = self->priv;
8968   ClutterActorBox old = { 0, };
8969   ClutterLayoutInfo *info;
8970
8971   /* if we are setting the size on a top-level actor and the
8972    * backend only supports static top-levels (e.g. framebuffers)
8973    * then we ignore the passed value and we override it with
8974    * the stage implementation's preferred size.
8975    */
8976   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8977       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8978     return;
8979
8980   info = _clutter_actor_get_layout_info (self);
8981
8982   if (priv->min_height_set && min_height == info->minimum.height)
8983     return;
8984
8985   g_object_freeze_notify (G_OBJECT (self));
8986
8987   clutter_actor_store_old_geometry (self, &old);
8988
8989   info->minimum.height = min_height;
8990   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8991   clutter_actor_set_min_height_set (self, TRUE);
8992
8993   clutter_actor_notify_if_geometry_changed (self, &old);
8994
8995   g_object_thaw_notify (G_OBJECT (self));
8996
8997   clutter_actor_queue_relayout (self);
8998 }
8999
9000 static void
9001 clutter_actor_set_natural_width (ClutterActor *self,
9002                                  gfloat        natural_width)
9003 {
9004   ClutterActorPrivate *priv = self->priv;
9005   ClutterActorBox old = { 0, };
9006   ClutterLayoutInfo *info;
9007
9008   /* if we are setting the size on a top-level actor and the
9009    * backend only supports static top-levels (e.g. framebuffers)
9010    * then we ignore the passed value and we override it with
9011    * the stage implementation's preferred size.
9012    */
9013   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9014       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9015     return;
9016
9017   info = _clutter_actor_get_layout_info (self);
9018
9019   if (priv->natural_width_set && natural_width == info->natural.width)
9020     return;
9021
9022   g_object_freeze_notify (G_OBJECT (self));
9023
9024   clutter_actor_store_old_geometry (self, &old);
9025
9026   info->natural.width = natural_width;
9027   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
9028   clutter_actor_set_natural_width_set (self, TRUE);
9029
9030   clutter_actor_notify_if_geometry_changed (self, &old);
9031
9032   g_object_thaw_notify (G_OBJECT (self));
9033
9034   clutter_actor_queue_relayout (self);
9035 }
9036
9037 static void
9038 clutter_actor_set_natural_height (ClutterActor *self,
9039                                   gfloat        natural_height)
9040 {
9041   ClutterActorPrivate *priv = self->priv;
9042   ClutterActorBox old = { 0, };
9043   ClutterLayoutInfo *info;
9044
9045   /* if we are setting the size on a top-level actor and the
9046    * backend only supports static top-levels (e.g. framebuffers)
9047    * then we ignore the passed value and we override it with
9048    * the stage implementation's preferred size.
9049    */
9050   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
9051       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
9052     return;
9053
9054   info = _clutter_actor_get_layout_info (self);
9055
9056   if (priv->natural_height_set && natural_height == info->natural.height)
9057     return;
9058
9059   g_object_freeze_notify (G_OBJECT (self));
9060
9061   clutter_actor_store_old_geometry (self, &old);
9062
9063   info->natural.height = natural_height;
9064   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
9065   clutter_actor_set_natural_height_set (self, TRUE);
9066
9067   clutter_actor_notify_if_geometry_changed (self, &old);
9068
9069   g_object_thaw_notify (G_OBJECT (self));
9070
9071   clutter_actor_queue_relayout (self);
9072 }
9073
9074 static void
9075 clutter_actor_set_min_width_set (ClutterActor *self,
9076                                  gboolean      use_min_width)
9077 {
9078   ClutterActorPrivate *priv = self->priv;
9079   ClutterActorBox old = { 0, };
9080
9081   if (priv->min_width_set == (use_min_width != FALSE))
9082     return;
9083
9084   clutter_actor_store_old_geometry (self, &old);
9085
9086   priv->min_width_set = use_min_width != FALSE;
9087   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
9088
9089   clutter_actor_notify_if_geometry_changed (self, &old);
9090
9091   clutter_actor_queue_relayout (self);
9092 }
9093
9094 static void
9095 clutter_actor_set_min_height_set (ClutterActor *self,
9096                                   gboolean      use_min_height)
9097 {
9098   ClutterActorPrivate *priv = self->priv;
9099   ClutterActorBox old = { 0, };
9100
9101   if (priv->min_height_set == (use_min_height != FALSE))
9102     return;
9103
9104   clutter_actor_store_old_geometry (self, &old);
9105
9106   priv->min_height_set = use_min_height != FALSE;
9107   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
9108
9109   clutter_actor_notify_if_geometry_changed (self, &old);
9110
9111   clutter_actor_queue_relayout (self);
9112 }
9113
9114 static void
9115 clutter_actor_set_natural_width_set (ClutterActor *self,
9116                                      gboolean      use_natural_width)
9117 {
9118   ClutterActorPrivate *priv = self->priv;
9119   ClutterActorBox old = { 0, };
9120
9121   if (priv->natural_width_set == (use_natural_width != FALSE))
9122     return;
9123
9124   clutter_actor_store_old_geometry (self, &old);
9125
9126   priv->natural_width_set = use_natural_width != FALSE;
9127   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9128
9129   clutter_actor_notify_if_geometry_changed (self, &old);
9130
9131   clutter_actor_queue_relayout (self);
9132 }
9133
9134 static void
9135 clutter_actor_set_natural_height_set (ClutterActor *self,
9136                                       gboolean      use_natural_height)
9137 {
9138   ClutterActorPrivate *priv = self->priv;
9139   ClutterActorBox old = { 0, };
9140
9141   if (priv->natural_height_set == (use_natural_height != FALSE))
9142     return;
9143
9144   clutter_actor_store_old_geometry (self, &old);
9145
9146   priv->natural_height_set = use_natural_height != FALSE;
9147   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9148
9149   clutter_actor_notify_if_geometry_changed (self, &old);
9150
9151   clutter_actor_queue_relayout (self);
9152 }
9153
9154 /**
9155  * clutter_actor_set_request_mode:
9156  * @self: a #ClutterActor
9157  * @mode: the request mode
9158  *
9159  * Sets the geometry request mode of @self.
9160  *
9161  * The @mode determines the order for invoking
9162  * clutter_actor_get_preferred_width() and
9163  * clutter_actor_get_preferred_height()
9164  *
9165  * Since: 1.2
9166  */
9167 void
9168 clutter_actor_set_request_mode (ClutterActor       *self,
9169                                 ClutterRequestMode  mode)
9170 {
9171   ClutterActorPrivate *priv;
9172
9173   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9174
9175   priv = self->priv;
9176
9177   if (priv->request_mode == mode)
9178     return;
9179
9180   priv->request_mode = mode;
9181
9182   priv->needs_width_request = TRUE;
9183   priv->needs_height_request = TRUE;
9184
9185   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9186
9187   clutter_actor_queue_relayout (self);
9188 }
9189
9190 /**
9191  * clutter_actor_get_request_mode:
9192  * @self: a #ClutterActor
9193  *
9194  * Retrieves the geometry request mode of @self
9195  *
9196  * Return value: the request mode for the actor
9197  *
9198  * Since: 1.2
9199  */
9200 ClutterRequestMode
9201 clutter_actor_get_request_mode (ClutterActor *self)
9202 {
9203   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9204                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9205
9206   return self->priv->request_mode;
9207 }
9208
9209 /* variant of set_width() without checks and without notification
9210  * freeze+thaw, for internal usage only
9211  */
9212 static inline void
9213 clutter_actor_set_width_internal (ClutterActor *self,
9214                                   gfloat        width)
9215 {
9216   if (width >= 0)
9217     {
9218       /* the Stage will use the :min-width to control the minimum
9219        * width to be resized to, so we should not be setting it
9220        * along with the :natural-width
9221        */
9222       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9223         clutter_actor_set_min_width (self, width);
9224
9225       clutter_actor_set_natural_width (self, width);
9226     }
9227   else
9228     {
9229       /* we only unset the :natural-width for the Stage */
9230       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9231         clutter_actor_set_min_width_set (self, FALSE);
9232
9233       clutter_actor_set_natural_width_set (self, FALSE);
9234     }
9235 }
9236
9237 /* variant of set_height() without checks and without notification
9238  * freeze+thaw, for internal usage only
9239  */
9240 static inline void
9241 clutter_actor_set_height_internal (ClutterActor *self,
9242                                    gfloat        height)
9243 {
9244   if (height >= 0)
9245     {
9246       /* see the comment above in set_width_internal() */
9247       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9248         clutter_actor_set_min_height (self, height);
9249
9250       clutter_actor_set_natural_height (self, height);
9251     }
9252   else
9253     {
9254       /* see the comment above in set_width_internal() */
9255       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9256         clutter_actor_set_min_height_set (self, FALSE);
9257
9258       clutter_actor_set_natural_height_set (self, FALSE);
9259     }
9260 }
9261
9262 static void
9263 clutter_actor_set_size_internal (ClutterActor      *self,
9264                                  const ClutterSize *size)
9265 {
9266   if (size != NULL)
9267     {
9268       clutter_actor_set_width_internal (self, size->width);
9269       clutter_actor_set_height_internal (self, size->height);
9270     }
9271   else
9272     {
9273       clutter_actor_set_width_internal (self, -1);
9274       clutter_actor_set_height_internal (self, -1);
9275     }
9276 }
9277
9278 /**
9279  * clutter_actor_set_size:
9280  * @self: A #ClutterActor
9281  * @width: New width of actor in pixels, or -1
9282  * @height: New height of actor in pixels, or -1
9283  *
9284  * Sets the actor's size request in pixels. This overrides any
9285  * "normal" size request the actor would have. For example
9286  * a text actor might normally request the size of the text;
9287  * this function would force a specific size instead.
9288  *
9289  * If @width and/or @height are -1 the actor will use its
9290  * "normal" size request instead of overriding it, i.e.
9291  * you can "unset" the size with -1.
9292  *
9293  * This function sets or unsets both the minimum and natural size.
9294  */
9295 void
9296 clutter_actor_set_size (ClutterActor *self,
9297                         gfloat        width,
9298                         gfloat        height)
9299 {
9300   ClutterSize new_size;
9301
9302   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9303
9304   clutter_size_init (&new_size, width, height);
9305
9306   if (_clutter_actor_get_transition (self, obj_props[PROP_SIZE]) == NULL)
9307     {
9308       /* minor optimization: if we don't have a duration then we can
9309        * skip the get_size() below, to avoid the chance of going through
9310        * get_preferred_width() and get_preferred_height() just to jump to
9311        * a new desired size
9312        */
9313       if (clutter_actor_get_easing_duration (self) == 0)
9314         {
9315           g_object_freeze_notify (G_OBJECT (self));
9316
9317           clutter_actor_set_size_internal (self, &new_size);
9318
9319           g_object_thaw_notify (G_OBJECT (self));
9320
9321           return;
9322         }
9323       else
9324         {
9325           ClutterSize cur_size;
9326
9327           clutter_size_init (&cur_size,
9328                              clutter_actor_get_width (self),
9329                              clutter_actor_get_height (self));
9330
9331          _clutter_actor_create_transition (self,
9332                                            obj_props[PROP_SIZE],
9333                                            &cur_size,
9334                                            &new_size);
9335         }
9336     }
9337   else
9338     _clutter_actor_update_transition (self, obj_props[PROP_SIZE], &new_size);
9339
9340   clutter_actor_queue_relayout (self);
9341 }
9342
9343 /**
9344  * clutter_actor_get_size:
9345  * @self: A #ClutterActor
9346  * @width: (out) (allow-none): return location for the width, or %NULL.
9347  * @height: (out) (allow-none): return location for the height, or %NULL.
9348  *
9349  * This function tries to "do what you mean" and return
9350  * the size an actor will have. If the actor has a valid
9351  * allocation, the allocation will be returned; otherwise,
9352  * the actors natural size request will be returned.
9353  *
9354  * If you care whether you get the request vs. the allocation, you
9355  * should probably call a different function like
9356  * clutter_actor_get_allocation_box() or
9357  * clutter_actor_get_preferred_width().
9358  *
9359  * Since: 0.2
9360  */
9361 void
9362 clutter_actor_get_size (ClutterActor *self,
9363                         gfloat       *width,
9364                         gfloat       *height)
9365 {
9366   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9367
9368   if (width)
9369     *width = clutter_actor_get_width (self);
9370
9371   if (height)
9372     *height = clutter_actor_get_height (self);
9373 }
9374
9375 /**
9376  * clutter_actor_get_position:
9377  * @self: a #ClutterActor
9378  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9379  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9380  *
9381  * This function tries to "do what you mean" and tell you where the
9382  * actor is, prior to any transformations. Retrieves the fixed
9383  * position of an actor in pixels, if one has been set; otherwise, if
9384  * the allocation is valid, returns the actor's allocated position;
9385  * otherwise, returns 0,0.
9386  *
9387  * The returned position is in pixels.
9388  *
9389  * Since: 0.6
9390  */
9391 void
9392 clutter_actor_get_position (ClutterActor *self,
9393                             gfloat       *x,
9394                             gfloat       *y)
9395 {
9396   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9397
9398   if (x)
9399     *x = clutter_actor_get_x (self);
9400
9401   if (y)
9402     *y = clutter_actor_get_y (self);
9403 }
9404
9405 /**
9406  * clutter_actor_get_transformed_position:
9407  * @self: A #ClutterActor
9408  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9409  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9410  *
9411  * Gets the absolute position of an actor, in pixels relative to the stage.
9412  *
9413  * Since: 0.8
9414  */
9415 void
9416 clutter_actor_get_transformed_position (ClutterActor *self,
9417                                         gfloat       *x,
9418                                         gfloat       *y)
9419 {
9420   ClutterVertex v1;
9421   ClutterVertex v2;
9422
9423   v1.x = v1.y = v1.z = 0;
9424   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9425
9426   if (x)
9427     *x = v2.x;
9428
9429   if (y)
9430     *y = v2.y;
9431 }
9432
9433 /**
9434  * clutter_actor_get_transformed_size:
9435  * @self: A #ClutterActor
9436  * @width: (out) (allow-none): return location for the width, or %NULL
9437  * @height: (out) (allow-none): return location for the height, or %NULL
9438  *
9439  * Gets the absolute size of an actor in pixels, taking into account the
9440  * scaling factors.
9441  *
9442  * If the actor has a valid allocation, the allocated size will be used.
9443  * If the actor has not a valid allocation then the preferred size will
9444  * be transformed and returned.
9445  *
9446  * If you want the transformed allocation, see
9447  * clutter_actor_get_abs_allocation_vertices() instead.
9448  *
9449  * <note>When the actor (or one of its ancestors) is rotated around the
9450  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9451  * as a generic quadrangle; in that case this function returns the size
9452  * of the smallest rectangle that encapsulates the entire quad. Please
9453  * note that in this case no assumptions can be made about the relative
9454  * position of this envelope to the absolute position of the actor, as
9455  * returned by clutter_actor_get_transformed_position(); if you need this
9456  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9457  * to get the coords of the actual quadrangle.</note>
9458  *
9459  * Since: 0.8
9460  */
9461 void
9462 clutter_actor_get_transformed_size (ClutterActor *self,
9463                                     gfloat       *width,
9464                                     gfloat       *height)
9465 {
9466   ClutterActorPrivate *priv;
9467   ClutterVertex v[4];
9468   gfloat x_min, x_max, y_min, y_max;
9469   gint i;
9470
9471   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9472
9473   priv = self->priv;
9474
9475   /* if the actor hasn't been allocated yet, get the preferred
9476    * size and transform that
9477    */
9478   if (priv->needs_allocation)
9479     {
9480       gfloat natural_width, natural_height;
9481       ClutterActorBox box;
9482
9483       /* Make a fake allocation to transform.
9484        *
9485        * NB: _clutter_actor_transform_and_project_box expects a box in
9486        * the actor's coordinate space... */
9487
9488       box.x1 = 0;
9489       box.y1 = 0;
9490
9491       natural_width = natural_height = 0;
9492       clutter_actor_get_preferred_size (self, NULL, NULL,
9493                                         &natural_width,
9494                                         &natural_height);
9495
9496       box.x2 = natural_width;
9497       box.y2 = natural_height;
9498
9499       _clutter_actor_transform_and_project_box (self, &box, v);
9500     }
9501   else
9502     clutter_actor_get_abs_allocation_vertices (self, v);
9503
9504   x_min = x_max = v[0].x;
9505   y_min = y_max = v[0].y;
9506
9507   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9508     {
9509       if (v[i].x < x_min)
9510         x_min = v[i].x;
9511
9512       if (v[i].x > x_max)
9513         x_max = v[i].x;
9514
9515       if (v[i].y < y_min)
9516         y_min = v[i].y;
9517
9518       if (v[i].y > y_max)
9519         y_max = v[i].y;
9520     }
9521
9522   if (width)
9523     *width  = x_max - x_min;
9524
9525   if (height)
9526     *height = y_max - y_min;
9527 }
9528
9529 /**
9530  * clutter_actor_get_width:
9531  * @self: A #ClutterActor
9532  *
9533  * Retrieves the width of a #ClutterActor.
9534  *
9535  * If the actor has a valid allocation, this function will return the
9536  * width of the allocated area given to the actor.
9537  *
9538  * If the actor does not have a valid allocation, this function will
9539  * return the actor's natural width, that is the preferred width of
9540  * the actor.
9541  *
9542  * If you care whether you get the preferred width or the width that
9543  * has been assigned to the actor, you should probably call a different
9544  * function like clutter_actor_get_allocation_box() to retrieve the
9545  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9546  * preferred width.
9547  *
9548  * If an actor has a fixed width, for instance a width that has been
9549  * assigned using clutter_actor_set_width(), the width returned will
9550  * be the same value.
9551  *
9552  * Return value: the width of the actor, in pixels
9553  */
9554 gfloat
9555 clutter_actor_get_width (ClutterActor *self)
9556 {
9557   ClutterActorPrivate *priv;
9558
9559   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9560
9561   priv = self->priv;
9562
9563   if (priv->needs_allocation)
9564     {
9565       gfloat natural_width = 0;
9566
9567       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9568         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9569       else
9570         {
9571           gfloat natural_height = 0;
9572
9573           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9574           clutter_actor_get_preferred_width (self, natural_height,
9575                                              NULL,
9576                                              &natural_width);
9577         }
9578
9579       return natural_width;
9580     }
9581   else
9582     return priv->allocation.x2 - priv->allocation.x1;
9583 }
9584
9585 /**
9586  * clutter_actor_get_height:
9587  * @self: A #ClutterActor
9588  *
9589  * Retrieves the height of a #ClutterActor.
9590  *
9591  * If the actor has a valid allocation, this function will return the
9592  * height of the allocated area given to the actor.
9593  *
9594  * If the actor does not have a valid allocation, this function will
9595  * return the actor's natural height, that is the preferred height of
9596  * the actor.
9597  *
9598  * If you care whether you get the preferred height or the height that
9599  * has been assigned to the actor, you should probably call a different
9600  * function like clutter_actor_get_allocation_box() to retrieve the
9601  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9602  * preferred height.
9603  *
9604  * If an actor has a fixed height, for instance a height that has been
9605  * assigned using clutter_actor_set_height(), the height returned will
9606  * be the same value.
9607  *
9608  * Return value: the height of the actor, in pixels
9609  */
9610 gfloat
9611 clutter_actor_get_height (ClutterActor *self)
9612 {
9613   ClutterActorPrivate *priv;
9614
9615   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9616
9617   priv = self->priv;
9618
9619   if (priv->needs_allocation)
9620     {
9621       gfloat natural_height = 0;
9622
9623       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9624         {
9625           gfloat natural_width = 0;
9626
9627           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9628           clutter_actor_get_preferred_height (self, natural_width,
9629                                               NULL, &natural_height);
9630         }
9631       else
9632         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9633
9634       return natural_height;
9635     }
9636   else
9637     return priv->allocation.y2 - priv->allocation.y1;
9638 }
9639
9640 /**
9641  * clutter_actor_set_width:
9642  * @self: A #ClutterActor
9643  * @width: Requested new width for the actor, in pixels, or -1
9644  *
9645  * Forces a width on an actor, causing the actor's preferred width
9646  * and height (if any) to be ignored.
9647  *
9648  * If @width is -1 the actor will use its preferred width request
9649  * instead of overriding it, i.e. you can "unset" the width with -1.
9650  *
9651  * This function sets both the minimum and natural size of the actor.
9652  *
9653  * since: 0.2
9654  */
9655 void
9656 clutter_actor_set_width (ClutterActor *self,
9657                          gfloat        width)
9658 {
9659   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9660
9661   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9662     {
9663       float cur_size;
9664
9665       /* minor optimization: if we don't have a duration
9666        * then we can skip the get_width() below, to avoid
9667        * the chance of going through get_preferred_width()
9668        * just to jump to a new desired width.
9669        */
9670       if (clutter_actor_get_easing_duration (self) == 0)
9671         {
9672           g_object_freeze_notify (G_OBJECT (self));
9673
9674           clutter_actor_set_width_internal (self, width);
9675
9676           g_object_thaw_notify (G_OBJECT (self));
9677
9678           return;
9679         }
9680       else
9681         cur_size = clutter_actor_get_width (self);
9682
9683       _clutter_actor_create_transition (self,
9684                                         obj_props[PROP_WIDTH],
9685                                         cur_size,
9686                                         width);
9687     }
9688   else
9689     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9690 }
9691
9692 /**
9693  * clutter_actor_set_height:
9694  * @self: A #ClutterActor
9695  * @height: Requested new height for the actor, in pixels, or -1
9696  *
9697  * Forces a height on an actor, causing the actor's preferred width
9698  * and height (if any) to be ignored.
9699  *
9700  * If @height is -1 the actor will use its preferred height instead of
9701  * overriding it, i.e. you can "unset" the height with -1.
9702  *
9703  * This function sets both the minimum and natural size of the actor.
9704  *
9705  * since: 0.2
9706  */
9707 void
9708 clutter_actor_set_height (ClutterActor *self,
9709                           gfloat        height)
9710 {
9711   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9712
9713   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9714     {
9715       float cur_size;
9716
9717       /* see the comment in clutter_actor_set_width() above */
9718       if (clutter_actor_get_easing_duration (self) == 0)
9719         {
9720           g_object_freeze_notify (G_OBJECT (self));
9721
9722           clutter_actor_set_height_internal (self, height);
9723
9724           g_object_thaw_notify (G_OBJECT (self));
9725
9726           return;
9727         }
9728       else
9729         cur_size = clutter_actor_get_height (self);
9730
9731       _clutter_actor_create_transition (self,
9732                                         obj_props[PROP_HEIGHT],
9733                                         cur_size,
9734                                         height);
9735     }
9736   else
9737     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9738 }
9739
9740 static inline void
9741 clutter_actor_set_x_internal (ClutterActor *self,
9742                               float         x)
9743 {
9744   ClutterActorPrivate *priv = self->priv;
9745   ClutterLayoutInfo *linfo;
9746   ClutterActorBox old = { 0, };
9747
9748   linfo = _clutter_actor_get_layout_info (self);
9749
9750   if (priv->position_set && linfo->fixed_pos.x == x)
9751     return;
9752
9753   clutter_actor_store_old_geometry (self, &old);
9754
9755   linfo->fixed_pos.x = x;
9756   clutter_actor_set_fixed_position_set (self, TRUE);
9757
9758   clutter_actor_notify_if_geometry_changed (self, &old);
9759
9760   clutter_actor_queue_relayout (self);
9761 }
9762
9763 static inline void
9764 clutter_actor_set_y_internal (ClutterActor *self,
9765                               float         y)
9766 {
9767   ClutterActorPrivate *priv = self->priv;
9768   ClutterLayoutInfo *linfo;
9769   ClutterActorBox old = { 0, };
9770
9771   linfo = _clutter_actor_get_layout_info (self);
9772
9773   if (priv->position_set && linfo->fixed_pos.y == y)
9774     return;
9775
9776   clutter_actor_store_old_geometry (self, &old);
9777
9778   linfo->fixed_pos.y = y;
9779   clutter_actor_set_fixed_position_set (self, TRUE);
9780
9781   clutter_actor_notify_if_geometry_changed (self, &old);
9782
9783   clutter_actor_queue_relayout (self);
9784 }
9785
9786 static void
9787 clutter_actor_set_position_internal (ClutterActor       *self,
9788                                      const ClutterPoint *position)
9789 {
9790   ClutterActorPrivate *priv = self->priv;
9791   ClutterLayoutInfo *linfo;
9792   ClutterActorBox old = { 0, };
9793
9794   linfo = _clutter_actor_get_layout_info (self);
9795
9796   if (priv->position_set &&
9797       clutter_point_equals (position, &linfo->fixed_pos))
9798     return;
9799
9800   clutter_actor_store_old_geometry (self, &old);
9801
9802   if (position != NULL)
9803     {
9804       linfo->fixed_pos = *position;
9805       clutter_actor_set_fixed_position_set (self, TRUE);
9806     }
9807   else
9808     clutter_actor_set_fixed_position_set (self, FALSE);
9809
9810   clutter_actor_notify_if_geometry_changed (self, &old);
9811
9812   clutter_actor_queue_relayout (self);
9813 }
9814
9815 /**
9816  * clutter_actor_set_x:
9817  * @self: a #ClutterActor
9818  * @x: the actor's position on the X axis
9819  *
9820  * Sets the actor's X coordinate, relative to its parent, in pixels.
9821  *
9822  * Overrides any layout manager and forces a fixed position for
9823  * the actor.
9824  *
9825  * The #ClutterActor:x property is animatable.
9826  *
9827  * Since: 0.6
9828  */
9829 void
9830 clutter_actor_set_x (ClutterActor *self,
9831                      gfloat        x)
9832 {
9833   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9834
9835   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9836     {
9837       float cur_position = clutter_actor_get_x (self);
9838
9839       _clutter_actor_create_transition (self, obj_props[PROP_X],
9840                                         cur_position,
9841                                         x);
9842     }
9843   else
9844     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9845 }
9846
9847 /**
9848  * clutter_actor_set_y:
9849  * @self: a #ClutterActor
9850  * @y: the actor's position on the Y axis
9851  *
9852  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9853  *
9854  * Overrides any layout manager and forces a fixed position for
9855  * the actor.
9856  *
9857  * The #ClutterActor:y property is animatable.
9858  *
9859  * Since: 0.6
9860  */
9861 void
9862 clutter_actor_set_y (ClutterActor *self,
9863                      gfloat        y)
9864 {
9865   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9866
9867   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9868     {
9869       float cur_position = clutter_actor_get_y (self);
9870
9871       _clutter_actor_create_transition (self, obj_props[PROP_Y],
9872                                         cur_position,
9873                                         y);
9874     }
9875   else
9876     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9877 }
9878
9879 /**
9880  * clutter_actor_get_x:
9881  * @self: A #ClutterActor
9882  *
9883  * Retrieves the X coordinate of a #ClutterActor.
9884  *
9885  * This function tries to "do what you mean", by returning the
9886  * correct value depending on the actor's state.
9887  *
9888  * If the actor has a valid allocation, this function will return
9889  * the X coordinate of the origin of the allocation box.
9890  *
9891  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9892  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9893  * function will return that coordinate.
9894  *
9895  * If both the allocation and a fixed position are missing, this function
9896  * will return 0.
9897  *
9898  * Return value: the X coordinate, in pixels, ignoring any
9899  *   transformation (i.e. scaling, rotation)
9900  */
9901 gfloat
9902 clutter_actor_get_x (ClutterActor *self)
9903 {
9904   ClutterActorPrivate *priv;
9905
9906   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9907
9908   priv = self->priv;
9909
9910   if (priv->needs_allocation)
9911     {
9912       if (priv->position_set)
9913         {
9914           const ClutterLayoutInfo *info;
9915
9916           info = _clutter_actor_get_layout_info_or_defaults (self);
9917
9918           return info->fixed_pos.x;
9919         }
9920       else
9921         return 0;
9922     }
9923   else
9924     return priv->allocation.x1;
9925 }
9926
9927 /**
9928  * clutter_actor_get_y:
9929  * @self: A #ClutterActor
9930  *
9931  * Retrieves the Y coordinate of a #ClutterActor.
9932  *
9933  * This function tries to "do what you mean", by returning the
9934  * correct value depending on the actor's state.
9935  *
9936  * If the actor has a valid allocation, this function will return
9937  * the Y coordinate of the origin of the allocation box.
9938  *
9939  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9940  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9941  * function will return that coordinate.
9942  *
9943  * If both the allocation and a fixed position are missing, this function
9944  * will return 0.
9945  *
9946  * Return value: the Y coordinate, in pixels, ignoring any
9947  *   transformation (i.e. scaling, rotation)
9948  */
9949 gfloat
9950 clutter_actor_get_y (ClutterActor *self)
9951 {
9952   ClutterActorPrivate *priv;
9953
9954   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9955
9956   priv = self->priv;
9957
9958   if (priv->needs_allocation)
9959     {
9960       if (priv->position_set)
9961         {
9962           const ClutterLayoutInfo *info;
9963
9964           info = _clutter_actor_get_layout_info_or_defaults (self);
9965
9966           return info->fixed_pos.y;
9967         }
9968       else
9969         return 0;
9970     }
9971   else
9972     return priv->allocation.y1;
9973 }
9974
9975 /**
9976  * clutter_actor_set_scale:
9977  * @self: A #ClutterActor
9978  * @scale_x: double factor to scale actor by horizontally.
9979  * @scale_y: double factor to scale actor by vertically.
9980  *
9981  * Scales an actor with the given factors. The scaling is relative to
9982  * the scale center and the anchor point. The scale center is
9983  * unchanged by this function and defaults to 0,0.
9984  *
9985  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9986  * animatable.
9987  *
9988  * Since: 0.2
9989  */
9990 void
9991 clutter_actor_set_scale (ClutterActor *self,
9992                          gdouble       scale_x,
9993                          gdouble       scale_y)
9994 {
9995   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9996
9997   g_object_freeze_notify (G_OBJECT (self));
9998
9999   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10000   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10001
10002   g_object_thaw_notify (G_OBJECT (self));
10003 }
10004
10005 /**
10006  * clutter_actor_set_scale_full:
10007  * @self: A #ClutterActor
10008  * @scale_x: double factor to scale actor by horizontally.
10009  * @scale_y: double factor to scale actor by vertically.
10010  * @center_x: X coordinate of the center of the scale.
10011  * @center_y: Y coordinate of the center of the scale
10012  *
10013  * Scales an actor with the given factors around the given center
10014  * point. The center point is specified in pixels relative to the
10015  * anchor point (usually the top left corner of the actor).
10016  *
10017  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
10018  * are animatable.
10019  *
10020  * Since: 1.0
10021  */
10022 void
10023 clutter_actor_set_scale_full (ClutterActor *self,
10024                               gdouble       scale_x,
10025                               gdouble       scale_y,
10026                               gfloat        center_x,
10027                               gfloat        center_y)
10028 {
10029   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10030
10031   g_object_freeze_notify (G_OBJECT (self));
10032
10033   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10034   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10035   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
10036   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
10037
10038   g_object_thaw_notify (G_OBJECT (self));
10039 }
10040
10041 /**
10042  * clutter_actor_set_scale_with_gravity:
10043  * @self: A #ClutterActor
10044  * @scale_x: double factor to scale actor by horizontally.
10045  * @scale_y: double factor to scale actor by vertically.
10046  * @gravity: the location of the scale center expressed as a compass
10047  * direction.
10048  *
10049  * Scales an actor with the given factors around the given
10050  * center point. The center point is specified as one of the compass
10051  * directions in #ClutterGravity. For example, setting it to north
10052  * will cause the top of the actor to remain unchanged and the rest of
10053  * the actor to expand left, right and downwards.
10054  *
10055  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
10056  * animatable.
10057  *
10058  * Since: 1.0
10059  */
10060 void
10061 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
10062                                       gdouble         scale_x,
10063                                       gdouble         scale_y,
10064                                       ClutterGravity  gravity)
10065 {
10066   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10067
10068   g_object_freeze_notify (G_OBJECT (self));
10069
10070   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
10071   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
10072   clutter_actor_set_scale_gravity (self, gravity);
10073
10074   g_object_thaw_notify (G_OBJECT (self));
10075 }
10076
10077 /**
10078  * clutter_actor_get_scale:
10079  * @self: A #ClutterActor
10080  * @scale_x: (out) (allow-none): Location to store horizonal
10081  *   scale factor, or %NULL.
10082  * @scale_y: (out) (allow-none): Location to store vertical
10083  *   scale factor, or %NULL.
10084  *
10085  * Retrieves an actors scale factors.
10086  *
10087  * Since: 0.2
10088  */
10089 void
10090 clutter_actor_get_scale (ClutterActor *self,
10091                          gdouble      *scale_x,
10092                          gdouble      *scale_y)
10093 {
10094   const ClutterTransformInfo *info;
10095
10096   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10097
10098   info = _clutter_actor_get_transform_info_or_defaults (self);
10099
10100   if (scale_x)
10101     *scale_x = info->scale_x;
10102
10103   if (scale_y)
10104     *scale_y = info->scale_y;
10105 }
10106
10107 /**
10108  * clutter_actor_get_scale_center:
10109  * @self: A #ClutterActor
10110  * @center_x: (out) (allow-none): Location to store the X position
10111  *   of the scale center, or %NULL.
10112  * @center_y: (out) (allow-none): Location to store the Y position
10113  *   of the scale center, or %NULL.
10114  *
10115  * Retrieves the scale center coordinate in pixels relative to the top
10116  * left corner of the actor. If the scale center was specified using a
10117  * #ClutterGravity this will calculate the pixel offset using the
10118  * current size of the actor.
10119  *
10120  * Since: 1.0
10121  */
10122 void
10123 clutter_actor_get_scale_center (ClutterActor *self,
10124                                 gfloat       *center_x,
10125                                 gfloat       *center_y)
10126 {
10127   const ClutterTransformInfo *info;
10128
10129   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10130
10131   info = _clutter_actor_get_transform_info_or_defaults (self);
10132
10133   clutter_anchor_coord_get_units (self, &info->scale_center,
10134                                   center_x,
10135                                   center_y,
10136                                   NULL);
10137 }
10138
10139 /**
10140  * clutter_actor_get_scale_gravity:
10141  * @self: A #ClutterActor
10142  *
10143  * Retrieves the scale center as a compass direction. If the scale
10144  * center was specified in pixels or units this will return
10145  * %CLUTTER_GRAVITY_NONE.
10146  *
10147  * Return value: the scale gravity
10148  *
10149  * Since: 1.0
10150  */
10151 ClutterGravity
10152 clutter_actor_get_scale_gravity (ClutterActor *self)
10153 {
10154   const ClutterTransformInfo *info;
10155
10156   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
10157
10158   info = _clutter_actor_get_transform_info_or_defaults (self);
10159
10160   return clutter_anchor_coord_get_gravity (&info->scale_center);
10161 }
10162
10163 static inline void
10164 clutter_actor_set_opacity_internal (ClutterActor *self,
10165                                     guint8        opacity)
10166 {
10167   ClutterActorPrivate *priv = self->priv;
10168
10169   if (priv->opacity != opacity)
10170     {
10171       priv->opacity = opacity;
10172
10173       /* Queue a redraw from the flatten effect so that it can use
10174          its cached image if available instead of having to redraw the
10175          actual actor. If it doesn't end up using the FBO then the
10176          effect is still able to continue the paint anyway. If there
10177          is no flatten effect yet then this is equivalent to queueing
10178          a full redraw */
10179       _clutter_actor_queue_redraw_full (self,
10180                                         0, /* flags */
10181                                         NULL, /* clip */
10182                                         priv->flatten_effect);
10183
10184       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
10185     }
10186 }
10187
10188 /**
10189  * clutter_actor_set_opacity:
10190  * @self: A #ClutterActor
10191  * @opacity: New opacity value for the actor.
10192  *
10193  * Sets the actor's opacity, with zero being completely transparent and
10194  * 255 (0xff) being fully opaque.
10195  *
10196  * The #ClutterActor:opacity property is animatable.
10197  */
10198 void
10199 clutter_actor_set_opacity (ClutterActor *self,
10200                            guint8        opacity)
10201 {
10202   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10203
10204   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10205     {
10206       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10207                                         self->priv->opacity,
10208                                         opacity);
10209     }
10210   else
10211     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10212 }
10213
10214 /*
10215  * clutter_actor_get_paint_opacity_internal:
10216  * @self: a #ClutterActor
10217  *
10218  * Retrieves the absolute opacity of the actor, as it appears on the stage
10219  *
10220  * This function does not do type checks
10221  *
10222  * Return value: the absolute opacity of the actor
10223  */
10224 static guint8
10225 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10226 {
10227   ClutterActorPrivate *priv = self->priv;
10228   ClutterActor *parent;
10229
10230   /* override the top-level opacity to always be 255; even in
10231    * case of ClutterStage:use-alpha being TRUE we want the rest
10232    * of the scene to be painted
10233    */
10234   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10235     return 255;
10236
10237   if (priv->opacity_override >= 0)
10238     return priv->opacity_override;
10239
10240   parent = priv->parent;
10241
10242   /* Factor in the actual actors opacity with parents */
10243   if (parent != NULL)
10244     {
10245       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10246
10247       if (opacity != 0xff)
10248         return (opacity * priv->opacity) / 0xff;
10249     }
10250
10251   return priv->opacity;
10252
10253 }
10254
10255 /**
10256  * clutter_actor_get_paint_opacity:
10257  * @self: A #ClutterActor
10258  *
10259  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10260  *
10261  * This function traverses the hierarchy chain and composites the opacity of
10262  * the actor with that of its parents.
10263  *
10264  * This function is intended for subclasses to use in the paint virtual
10265  * function, to paint themselves with the correct opacity.
10266  *
10267  * Return value: The actor opacity value.
10268  *
10269  * Since: 0.8
10270  */
10271 guint8
10272 clutter_actor_get_paint_opacity (ClutterActor *self)
10273 {
10274   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10275
10276   return clutter_actor_get_paint_opacity_internal (self);
10277 }
10278
10279 /**
10280  * clutter_actor_get_opacity:
10281  * @self: a #ClutterActor
10282  *
10283  * Retrieves the opacity value of an actor, as set by
10284  * clutter_actor_set_opacity().
10285  *
10286  * For retrieving the absolute opacity of the actor inside a paint
10287  * virtual function, see clutter_actor_get_paint_opacity().
10288  *
10289  * Return value: the opacity of the actor
10290  */
10291 guint8
10292 clutter_actor_get_opacity (ClutterActor *self)
10293 {
10294   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10295
10296   return self->priv->opacity;
10297 }
10298
10299 /**
10300  * clutter_actor_set_offscreen_redirect:
10301  * @self: A #ClutterActor
10302  * @redirect: New offscreen redirect flags for the actor.
10303  *
10304  * Defines the circumstances where the actor should be redirected into
10305  * an offscreen image. The offscreen image is used to flatten the
10306  * actor into a single image while painting for two main reasons.
10307  * Firstly, when the actor is painted a second time without any of its
10308  * contents changing it can simply repaint the cached image without
10309  * descending further down the actor hierarchy. Secondly, it will make
10310  * the opacity look correct even if there are overlapping primitives
10311  * in the actor.
10312  *
10313  * Caching the actor could in some cases be a performance win and in
10314  * some cases be a performance lose so it is important to determine
10315  * which value is right for an actor before modifying this value. For
10316  * example, there is never any reason to flatten an actor that is just
10317  * a single texture (such as a #ClutterTexture) because it is
10318  * effectively already cached in an image so the offscreen would be
10319  * redundant. Also if the actor contains primitives that are far apart
10320  * with a large transparent area in the middle (such as a large
10321  * CluterGroup with a small actor in the top left and a small actor in
10322  * the bottom right) then the cached image will contain the entire
10323  * image of the large area and the paint will waste time blending all
10324  * of the transparent pixels in the middle.
10325  *
10326  * The default method of implementing opacity on a container simply
10327  * forwards on the opacity to all of the children. If the children are
10328  * overlapping then it will appear as if they are two separate glassy
10329  * objects and there will be a break in the color where they
10330  * overlap. By redirecting to an offscreen buffer it will be as if the
10331  * two opaque objects are combined into one and then made transparent
10332  * which is usually what is expected.
10333  *
10334  * The image below demonstrates the difference between redirecting and
10335  * not. The image shows two Clutter groups, each containing a red and
10336  * a green rectangle which overlap. The opacity on the group is set to
10337  * 128 (which is 50%). When the offscreen redirect is not used, the
10338  * red rectangle can be seen through the blue rectangle as if the two
10339  * rectangles were separately transparent. When the redirect is used
10340  * the group as a whole is transparent instead so the red rectangle is
10341  * not visible where they overlap.
10342  *
10343  * <figure id="offscreen-redirect">
10344  *   <title>Sample of using an offscreen redirect for transparency</title>
10345  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10346  * </figure>
10347  *
10348  * The default value for this property is 0, so we effectively will
10349  * never redirect an actor offscreen by default. This means that there
10350  * are times that transparent actors may look glassy as described
10351  * above. The reason this is the default is because there is a
10352  * performance trade off between quality and performance here. In many
10353  * cases the default form of glassy opacity looks good enough, but if
10354  * it's not you will need to set the
10355  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10356  * redirection for opacity.
10357  *
10358  * Custom actors that don't contain any overlapping primitives are
10359  * recommended to override the has_overlaps() virtual to return %FALSE
10360  * for maximum efficiency.
10361  *
10362  * Since: 1.8
10363  */
10364 void
10365 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10366                                       ClutterOffscreenRedirect redirect)
10367 {
10368   ClutterActorPrivate *priv;
10369
10370   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10371
10372   priv = self->priv;
10373
10374   if (priv->offscreen_redirect != redirect)
10375     {
10376       priv->offscreen_redirect = redirect;
10377
10378       /* Queue a redraw from the effect so that it can use its cached
10379          image if available instead of having to redraw the actual
10380          actor. If it doesn't end up using the FBO then the effect is
10381          still able to continue the paint anyway. If there is no
10382          effect then this is equivalent to queuing a full redraw */
10383       _clutter_actor_queue_redraw_full (self,
10384                                         0, /* flags */
10385                                         NULL, /* clip */
10386                                         priv->flatten_effect);
10387
10388       g_object_notify_by_pspec (G_OBJECT (self),
10389                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10390     }
10391 }
10392
10393 /**
10394  * clutter_actor_get_offscreen_redirect:
10395  * @self: a #ClutterActor
10396  *
10397  * Retrieves whether to redirect the actor to an offscreen buffer, as
10398  * set by clutter_actor_set_offscreen_redirect().
10399  *
10400  * Return value: the value of the offscreen-redirect property of the actor
10401  *
10402  * Since: 1.8
10403  */
10404 ClutterOffscreenRedirect
10405 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10406 {
10407   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10408
10409   return self->priv->offscreen_redirect;
10410 }
10411
10412 /**
10413  * clutter_actor_set_name:
10414  * @self: A #ClutterActor
10415  * @name: Textual tag to apply to actor
10416  *
10417  * Sets the given name to @self. The name can be used to identify
10418  * a #ClutterActor.
10419  */
10420 void
10421 clutter_actor_set_name (ClutterActor *self,
10422                         const gchar  *name)
10423 {
10424   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10425
10426   g_free (self->priv->name);
10427   self->priv->name = g_strdup (name);
10428
10429   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10430 }
10431
10432 /**
10433  * clutter_actor_get_name:
10434  * @self: A #ClutterActor
10435  *
10436  * Retrieves the name of @self.
10437  *
10438  * Return value: the name of the actor, or %NULL. The returned string is
10439  *   owned by the actor and should not be modified or freed.
10440  */
10441 const gchar *
10442 clutter_actor_get_name (ClutterActor *self)
10443 {
10444   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10445
10446   return self->priv->name;
10447 }
10448
10449 /**
10450  * clutter_actor_get_gid:
10451  * @self: A #ClutterActor
10452  *
10453  * Retrieves the unique id for @self.
10454  *
10455  * Return value: Globally unique value for this object instance.
10456  *
10457  * Since: 0.6
10458  *
10459  * Deprecated: 1.8: The id is not used any longer.
10460  */
10461 guint32
10462 clutter_actor_get_gid (ClutterActor *self)
10463 {
10464   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10465
10466   return self->priv->id;
10467 }
10468
10469 static inline void
10470 clutter_actor_set_depth_internal (ClutterActor *self,
10471                                   float         depth)
10472 {
10473   ClutterTransformInfo *info;
10474
10475   info = _clutter_actor_get_transform_info (self);
10476
10477   if (info->depth != depth)
10478     {
10479       /* Sets Z value - XXX 2.0: should we invert? */
10480       info->depth = depth;
10481
10482       self->priv->transform_valid = FALSE;
10483
10484       /* FIXME - remove this crap; sadly, there are still containers
10485        * in Clutter that depend on this utter brain damage
10486        */
10487       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10488
10489       clutter_actor_queue_redraw (self);
10490
10491       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10492     }
10493 }
10494
10495 /**
10496  * clutter_actor_set_depth:
10497  * @self: a #ClutterActor
10498  * @depth: Z co-ord
10499  *
10500  * Sets the Z coordinate of @self to @depth.
10501  *
10502  * The unit used by @depth is dependant on the perspective setup. See
10503  * also clutter_stage_set_perspective().
10504  */
10505 void
10506 clutter_actor_set_depth (ClutterActor *self,
10507                          gfloat        depth)
10508 {
10509   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10510
10511   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10512     {
10513       const ClutterTransformInfo *info;
10514
10515       info = _clutter_actor_get_transform_info_or_defaults (self);
10516
10517       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10518                                         info->depth,
10519                                         depth);
10520     }
10521   else
10522     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10523
10524   clutter_actor_queue_redraw (self);
10525 }
10526
10527 /**
10528  * clutter_actor_get_depth:
10529  * @self: a #ClutterActor
10530  *
10531  * Retrieves the depth of @self.
10532  *
10533  * Return value: the depth of the actor
10534  */
10535 gfloat
10536 clutter_actor_get_depth (ClutterActor *self)
10537 {
10538   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10539
10540   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10541 }
10542
10543 /**
10544  * clutter_actor_set_rotation:
10545  * @self: a #ClutterActor
10546  * @axis: the axis of rotation
10547  * @angle: the angle of rotation
10548  * @x: X coordinate of the rotation center
10549  * @y: Y coordinate of the rotation center
10550  * @z: Z coordinate of the rotation center
10551  *
10552  * Sets the rotation angle of @self around the given axis.
10553  *
10554  * The rotation center coordinates used depend on the value of @axis:
10555  * <itemizedlist>
10556  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10557  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10558  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10559  * </itemizedlist>
10560  *
10561  * The rotation coordinates are relative to the anchor point of the
10562  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10563  * point is set, the upper left corner is assumed as the origin.
10564  *
10565  * Since: 0.8
10566  */
10567 void
10568 clutter_actor_set_rotation (ClutterActor      *self,
10569                             ClutterRotateAxis  axis,
10570                             gdouble            angle,
10571                             gfloat             x,
10572                             gfloat             y,
10573                             gfloat             z)
10574 {
10575   ClutterVertex v;
10576
10577   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10578
10579   v.x = x;
10580   v.y = y;
10581   v.z = z;
10582
10583   g_object_freeze_notify (G_OBJECT (self));
10584
10585   clutter_actor_set_rotation_angle (self, axis, angle);
10586   clutter_actor_set_rotation_center_internal (self, axis, &v);
10587
10588   g_object_thaw_notify (G_OBJECT (self));
10589 }
10590
10591 /**
10592  * clutter_actor_set_z_rotation_from_gravity:
10593  * @self: a #ClutterActor
10594  * @angle: the angle of rotation
10595  * @gravity: the center point of the rotation
10596  *
10597  * Sets the rotation angle of @self around the Z axis using the center
10598  * point specified as a compass point. For example to rotate such that
10599  * the center of the actor remains static you can use
10600  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10601  * will move accordingly.
10602  *
10603  * Since: 1.0
10604  */
10605 void
10606 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10607                                            gdouble         angle,
10608                                            ClutterGravity  gravity)
10609 {
10610   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10611
10612   if (gravity == CLUTTER_GRAVITY_NONE)
10613     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10614   else
10615     {
10616       GObject *obj = G_OBJECT (self);
10617       ClutterTransformInfo *info;
10618
10619       info = _clutter_actor_get_transform_info (self);
10620
10621       g_object_freeze_notify (obj);
10622
10623       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10624
10625       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10626       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10627       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10628
10629       g_object_thaw_notify (obj);
10630     }
10631 }
10632
10633 /**
10634  * clutter_actor_get_rotation:
10635  * @self: a #ClutterActor
10636  * @axis: the axis of rotation
10637  * @x: (out): return value for the X coordinate of the center of rotation
10638  * @y: (out): return value for the Y coordinate of the center of rotation
10639  * @z: (out): return value for the Z coordinate of the center of rotation
10640  *
10641  * Retrieves the angle and center of rotation on the given axis,
10642  * set using clutter_actor_set_rotation().
10643  *
10644  * Return value: the angle of rotation
10645  *
10646  * Since: 0.8
10647  */
10648 gdouble
10649 clutter_actor_get_rotation (ClutterActor      *self,
10650                             ClutterRotateAxis  axis,
10651                             gfloat            *x,
10652                             gfloat            *y,
10653                             gfloat            *z)
10654 {
10655   const ClutterTransformInfo *info;
10656   const AnchorCoord *anchor_coord;
10657   gdouble retval = 0;
10658
10659   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10660
10661   info = _clutter_actor_get_transform_info_or_defaults (self);
10662
10663   switch (axis)
10664     {
10665     case CLUTTER_X_AXIS:
10666       anchor_coord = &info->rx_center;
10667       retval = info->rx_angle;
10668       break;
10669
10670     case CLUTTER_Y_AXIS:
10671       anchor_coord = &info->ry_center;
10672       retval = info->ry_angle;
10673       break;
10674
10675     case CLUTTER_Z_AXIS:
10676       anchor_coord = &info->rz_center;
10677       retval = info->rz_angle;
10678       break;
10679
10680     default:
10681       anchor_coord = NULL;
10682       retval = 0.0;
10683       break;
10684     }
10685
10686   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10687
10688   return retval;
10689 }
10690
10691 /**
10692  * clutter_actor_get_z_rotation_gravity:
10693  * @self: A #ClutterActor
10694  *
10695  * Retrieves the center for the rotation around the Z axis as a
10696  * compass direction. If the center was specified in pixels or units
10697  * this will return %CLUTTER_GRAVITY_NONE.
10698  *
10699  * Return value: the Z rotation center
10700  *
10701  * Since: 1.0
10702  */
10703 ClutterGravity
10704 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10705 {
10706   const ClutterTransformInfo *info;
10707
10708   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10709
10710   info = _clutter_actor_get_transform_info_or_defaults (self);
10711
10712   return clutter_anchor_coord_get_gravity (&info->rz_center);
10713 }
10714
10715 /**
10716  * clutter_actor_set_clip:
10717  * @self: A #ClutterActor
10718  * @xoff: X offset of the clip rectangle
10719  * @yoff: Y offset of the clip rectangle
10720  * @width: Width of the clip rectangle
10721  * @height: Height of the clip rectangle
10722  *
10723  * Sets clip area for @self. The clip area is always computed from the
10724  * upper left corner of the actor, even if the anchor point is set
10725  * otherwise.
10726  *
10727  * Since: 0.6
10728  */
10729 void
10730 clutter_actor_set_clip (ClutterActor *self,
10731                         gfloat        xoff,
10732                         gfloat        yoff,
10733                         gfloat        width,
10734                         gfloat        height)
10735 {
10736   ClutterActorPrivate *priv;
10737
10738   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10739
10740   priv = self->priv;
10741
10742   if (priv->has_clip &&
10743       priv->clip.x == xoff &&
10744       priv->clip.y == yoff &&
10745       priv->clip.width == width &&
10746       priv->clip.height == height)
10747     return;
10748
10749   priv->clip.x = xoff;
10750   priv->clip.y = yoff;
10751   priv->clip.width = width;
10752   priv->clip.height = height;
10753
10754   priv->has_clip = TRUE;
10755
10756   clutter_actor_queue_redraw (self);
10757
10758   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10759   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10760 }
10761
10762 /**
10763  * clutter_actor_remove_clip:
10764  * @self: A #ClutterActor
10765  *
10766  * Removes clip area from @self.
10767  */
10768 void
10769 clutter_actor_remove_clip (ClutterActor *self)
10770 {
10771   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10772
10773   if (!self->priv->has_clip)
10774     return;
10775
10776   self->priv->has_clip = FALSE;
10777
10778   clutter_actor_queue_redraw (self);
10779
10780   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10781 }
10782
10783 /**
10784  * clutter_actor_has_clip:
10785  * @self: a #ClutterActor
10786  *
10787  * Determines whether the actor has a clip area set or not.
10788  *
10789  * Return value: %TRUE if the actor has a clip area set.
10790  *
10791  * Since: 0.1.1
10792  */
10793 gboolean
10794 clutter_actor_has_clip (ClutterActor *self)
10795 {
10796   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10797
10798   return self->priv->has_clip;
10799 }
10800
10801 /**
10802  * clutter_actor_get_clip:
10803  * @self: a #ClutterActor
10804  * @xoff: (out) (allow-none): return location for the X offset of
10805  *   the clip rectangle, or %NULL
10806  * @yoff: (out) (allow-none): return location for the Y offset of
10807  *   the clip rectangle, or %NULL
10808  * @width: (out) (allow-none): return location for the width of
10809  *   the clip rectangle, or %NULL
10810  * @height: (out) (allow-none): return location for the height of
10811  *   the clip rectangle, or %NULL
10812  *
10813  * Gets the clip area for @self, if any is set
10814  *
10815  * Since: 0.6
10816  */
10817 void
10818 clutter_actor_get_clip (ClutterActor *self,
10819                         gfloat       *xoff,
10820                         gfloat       *yoff,
10821                         gfloat       *width,
10822                         gfloat       *height)
10823 {
10824   ClutterActorPrivate *priv;
10825
10826   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10827
10828   priv = self->priv;
10829
10830   if (!priv->has_clip)
10831     return;
10832
10833   if (xoff != NULL)
10834     *xoff = priv->clip.x;
10835
10836   if (yoff != NULL)
10837     *yoff = priv->clip.y;
10838
10839   if (width != NULL)
10840     *width = priv->clip.width;
10841
10842   if (height != NULL)
10843     *height = priv->clip.height;
10844 }
10845
10846 /**
10847  * clutter_actor_get_children:
10848  * @self: a #ClutterActor
10849  *
10850  * Retrieves the list of children of @self.
10851  *
10852  * Return value: (transfer container) (element-type ClutterActor): A newly
10853  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10854  *   done.
10855  *
10856  * Since: 1.10
10857  */
10858 GList *
10859 clutter_actor_get_children (ClutterActor *self)
10860 {
10861   ClutterActor *iter;
10862   GList *res;
10863
10864   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10865
10866   /* we walk the list backward so that we can use prepend(),
10867    * which is O(1)
10868    */
10869   for (iter = self->priv->last_child, res = NULL;
10870        iter != NULL;
10871        iter = iter->priv->prev_sibling)
10872     {
10873       res = g_list_prepend (res, iter);
10874     }
10875
10876   return res;
10877 }
10878
10879 /*< private >
10880  * insert_child_at_depth:
10881  * @self: a #ClutterActor
10882  * @child: a #ClutterActor
10883  *
10884  * Inserts @child inside the list of children held by @self, using
10885  * the depth as the insertion criteria.
10886  *
10887  * This sadly makes the insertion not O(1), but we can keep the
10888  * list sorted so that the painters algorithm we use for painting
10889  * the children will work correctly.
10890  */
10891 static void
10892 insert_child_at_depth (ClutterActor *self,
10893                        ClutterActor *child,
10894                        gpointer      dummy G_GNUC_UNUSED)
10895 {
10896   ClutterActor *iter;
10897   float child_depth;
10898
10899   child->priv->parent = self;
10900
10901   child_depth =
10902     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10903
10904   /* special-case the first child */
10905   if (self->priv->n_children == 0)
10906     {
10907       self->priv->first_child = child;
10908       self->priv->last_child = child;
10909
10910       child->priv->next_sibling = NULL;
10911       child->priv->prev_sibling = NULL;
10912
10913       return;
10914     }
10915
10916   /* Find the right place to insert the child so that it will still be
10917      sorted and the child will be after all of the actors at the same
10918      dept */
10919   for (iter = self->priv->first_child;
10920        iter != NULL;
10921        iter = iter->priv->next_sibling)
10922     {
10923       float iter_depth;
10924
10925       iter_depth =
10926         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10927
10928       if (iter_depth > child_depth)
10929         break;
10930     }
10931
10932   if (iter != NULL)
10933     {
10934       ClutterActor *tmp = iter->priv->prev_sibling;
10935
10936       if (tmp != NULL)
10937         tmp->priv->next_sibling = child;
10938
10939       /* Insert the node before the found one */
10940       child->priv->prev_sibling = iter->priv->prev_sibling;
10941       child->priv->next_sibling = iter;
10942       iter->priv->prev_sibling = child;
10943     }
10944   else
10945     {
10946       ClutterActor *tmp = self->priv->last_child;
10947
10948       if (tmp != NULL)
10949         tmp->priv->next_sibling = child;
10950
10951       /* insert the node at the end of the list */
10952       child->priv->prev_sibling = self->priv->last_child;
10953       child->priv->next_sibling = NULL;
10954     }
10955
10956   if (child->priv->prev_sibling == NULL)
10957     self->priv->first_child = child;
10958
10959   if (child->priv->next_sibling == NULL)
10960     self->priv->last_child = child;
10961 }
10962
10963 static void
10964 insert_child_at_index (ClutterActor *self,
10965                        ClutterActor *child,
10966                        gpointer      data_)
10967 {
10968   gint index_ = GPOINTER_TO_INT (data_);
10969
10970   child->priv->parent = self;
10971
10972   if (index_ == 0)
10973     {
10974       ClutterActor *tmp = self->priv->first_child;
10975
10976       if (tmp != NULL)
10977         tmp->priv->prev_sibling = child;
10978
10979       child->priv->prev_sibling = NULL;
10980       child->priv->next_sibling = tmp;
10981     }
10982   else if (index_ < 0 || index_ >= self->priv->n_children)
10983     {
10984       ClutterActor *tmp = self->priv->last_child;
10985
10986       if (tmp != NULL)
10987         tmp->priv->next_sibling = child;
10988
10989       child->priv->prev_sibling = tmp;
10990       child->priv->next_sibling = NULL;
10991     }
10992   else
10993     {
10994       ClutterActor *iter;
10995       int i;
10996
10997       for (iter = self->priv->first_child, i = 0;
10998            iter != NULL;
10999            iter = iter->priv->next_sibling, i += 1)
11000         {
11001           if (index_ == i)
11002             {
11003               ClutterActor *tmp = iter->priv->prev_sibling;
11004
11005               child->priv->prev_sibling = tmp;
11006               child->priv->next_sibling = iter;
11007
11008               iter->priv->prev_sibling = child;
11009
11010               if (tmp != NULL)
11011                 tmp->priv->next_sibling = child;
11012
11013               break;
11014             }
11015         }
11016     }
11017
11018   if (child->priv->prev_sibling == NULL)
11019     self->priv->first_child = child;
11020
11021   if (child->priv->next_sibling == NULL)
11022     self->priv->last_child = child;
11023 }
11024
11025 static void
11026 insert_child_above (ClutterActor *self,
11027                     ClutterActor *child,
11028                     gpointer      data)
11029 {
11030   ClutterActor *sibling = data;
11031
11032   child->priv->parent = self;
11033
11034   if (sibling == NULL)
11035     sibling = self->priv->last_child;
11036
11037   child->priv->prev_sibling = sibling;
11038
11039   if (sibling != NULL)
11040     {
11041       ClutterActor *tmp = sibling->priv->next_sibling;
11042
11043       child->priv->next_sibling = tmp;
11044
11045       if (tmp != NULL)
11046         tmp->priv->prev_sibling = child;
11047
11048       sibling->priv->next_sibling = child;
11049     }
11050   else
11051     child->priv->next_sibling = NULL;
11052
11053   if (child->priv->prev_sibling == NULL)
11054     self->priv->first_child = child;
11055
11056   if (child->priv->next_sibling == NULL)
11057     self->priv->last_child = child;
11058 }
11059
11060 static void
11061 insert_child_below (ClutterActor *self,
11062                     ClutterActor *child,
11063                     gpointer      data)
11064 {
11065   ClutterActor *sibling = data;
11066
11067   child->priv->parent = self;
11068
11069   if (sibling == NULL)
11070     sibling = self->priv->first_child;
11071
11072   child->priv->next_sibling = sibling;
11073
11074   if (sibling != NULL)
11075     {
11076       ClutterActor *tmp = sibling->priv->prev_sibling;
11077
11078       child->priv->prev_sibling = tmp;
11079
11080       if (tmp != NULL)
11081         tmp->priv->next_sibling = child;
11082
11083       sibling->priv->prev_sibling = child;
11084     }
11085   else
11086     child->priv->prev_sibling = NULL;
11087
11088   if (child->priv->prev_sibling == NULL)
11089     self->priv->first_child = child;
11090
11091   if (child->priv->next_sibling == NULL)
11092     self->priv->last_child = child;
11093 }
11094
11095 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
11096                                            ClutterActor *child,
11097                                            gpointer      data);
11098
11099 typedef enum {
11100   ADD_CHILD_CREATE_META        = 1 << 0,
11101   ADD_CHILD_EMIT_PARENT_SET    = 1 << 1,
11102   ADD_CHILD_EMIT_ACTOR_ADDED   = 1 << 2,
11103   ADD_CHILD_CHECK_STATE        = 1 << 3,
11104   ADD_CHILD_NOTIFY_FIRST_LAST  = 1 << 4,
11105   ADD_CHILD_SHOW_ON_SET_PARENT = 1 << 5,
11106
11107   /* default flags for public API */
11108   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
11109                                ADD_CHILD_EMIT_PARENT_SET |
11110                                ADD_CHILD_EMIT_ACTOR_ADDED |
11111                                ADD_CHILD_CHECK_STATE |
11112                                ADD_CHILD_NOTIFY_FIRST_LAST |
11113                                ADD_CHILD_SHOW_ON_SET_PARENT,
11114
11115   /* flags for legacy/deprecated API */
11116   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
11117                                ADD_CHILD_CHECK_STATE |
11118                                ADD_CHILD_NOTIFY_FIRST_LAST |
11119                                ADD_CHILD_SHOW_ON_SET_PARENT
11120 } ClutterActorAddChildFlags;
11121
11122 /*< private >
11123  * clutter_actor_add_child_internal:
11124  * @self: a #ClutterActor
11125  * @child: a #ClutterActor
11126  * @flags: control flags for actions
11127  * @add_func: delegate function
11128  * @data: (closure): data to pass to @add_func
11129  *
11130  * Adds @child to the list of children of @self.
11131  *
11132  * The actual insertion inside the list is delegated to @add_func: this
11133  * function will just set up the state, perform basic checks, and emit
11134  * signals.
11135  *
11136  * The @flags argument is used to perform additional operations.
11137  */
11138 static inline void
11139 clutter_actor_add_child_internal (ClutterActor              *self,
11140                                   ClutterActor              *child,
11141                                   ClutterActorAddChildFlags  flags,
11142                                   ClutterActorAddChildFunc   add_func,
11143                                   gpointer                   data)
11144 {
11145   ClutterTextDirection text_dir;
11146   gboolean create_meta;
11147   gboolean emit_parent_set, emit_actor_added;
11148   gboolean check_state;
11149   gboolean notify_first_last;
11150   gboolean show_on_set_parent;
11151   ClutterActor *old_first_child, *old_last_child;
11152
11153   if (child->priv->parent != NULL)
11154     {
11155       g_warning ("The actor '%s' already has a parent, '%s'. You must "
11156                  "use clutter_actor_remove_child() first.",
11157                  _clutter_actor_get_debug_name (child),
11158                  _clutter_actor_get_debug_name (child->priv->parent));
11159       return;
11160     }
11161
11162   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
11163     {
11164       g_warning ("The actor '%s' is a top-level actor, and cannot be "
11165                  "a child of another actor.",
11166                  _clutter_actor_get_debug_name (child));
11167       return;
11168     }
11169
11170 #if 0
11171   /* XXX - this check disallows calling methods that change the stacking
11172    * order within the destruction sequence, by triggering a critical
11173    * warning first, and leaving the actor in an undefined state, which
11174    * then ends up being caught by an assertion.
11175    *
11176    * the reproducible sequence is:
11177    *
11178    *   - actor gets destroyed;
11179    *   - another actor, linked to the first, will try to change the
11180    *     stacking order of the first actor;
11181    *   - changing the stacking order is a composite operation composed
11182    *     by the following steps:
11183    *     1. ref() the child;
11184    *     2. remove_child_internal(), which removes the reference;
11185    *     3. add_child_internal(), which adds a reference;
11186    *   - the state of the actor is not changed between (2) and (3), as
11187    *     it could be an expensive recomputation;
11188    *   - if (3) bails out, then the actor is in an undefined state, but
11189    *     still alive;
11190    *   - the destruction sequence terminates, but the actor is unparented
11191    *     while its state indicates being parented instead.
11192    *   - assertion failure.
11193    *
11194    * the obvious fix would be to decompose each set_child_*_sibling()
11195    * method into proper remove_child()/add_child(), with state validation;
11196    * this may cause excessive work, though, and trigger a cascade of other
11197    * bugs in code that assumes that a change in the stacking order is an
11198    * atomic operation.
11199    *
11200    * another potential fix is to just remove this check here, and let
11201    * code doing stacking order changes inside the destruction sequence
11202    * of an actor continue doing the work.
11203    *
11204    * the third fix is to silently bail out early from every
11205    * set_child_*_sibling() and set_child_at_index() method, and avoid
11206    * doing work.
11207    *
11208    * I have a preference for the second solution, since it involves the
11209    * least amount of work, and the least amount of code duplication.
11210    *
11211    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11212    */
11213   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11214     {
11215       g_warning ("The actor '%s' is currently being destroyed, and "
11216                  "cannot be added as a child of another actor.",
11217                  _clutter_actor_get_debug_name (child));
11218       return;
11219     }
11220 #endif
11221
11222   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11223   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11224   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11225   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11226   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11227   show_on_set_parent = (flags & ADD_CHILD_SHOW_ON_SET_PARENT) != 0;
11228
11229   old_first_child = self->priv->first_child;
11230   old_last_child = self->priv->last_child;
11231
11232   g_object_freeze_notify (G_OBJECT (self));
11233
11234   if (create_meta)
11235     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11236
11237   g_object_ref_sink (child);
11238   child->priv->parent = NULL;
11239   child->priv->next_sibling = NULL;
11240   child->priv->prev_sibling = NULL;
11241
11242   /* delegate the actual insertion */
11243   add_func (self, child, data);
11244
11245   g_assert (child->priv->parent == self);
11246
11247   self->priv->n_children += 1;
11248
11249   self->priv->age += 1;
11250
11251   /* if push_internal() has been called then we automatically set
11252    * the flag on the actor
11253    */
11254   if (self->priv->internal_child)
11255     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11256
11257   /* clutter_actor_reparent() will emit ::parent-set for us */
11258   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11259     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11260
11261   if (check_state)
11262     {
11263       /* If parent is mapped or realized, we need to also be mapped or
11264        * realized once we're inside the parent.
11265        */
11266       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11267
11268       /* propagate the parent's text direction to the child */
11269       text_dir = clutter_actor_get_text_direction (self);
11270       clutter_actor_set_text_direction (child, text_dir);
11271     }
11272
11273   if (show_on_set_parent && child->priv->show_on_set_parent)
11274     clutter_actor_show (child);
11275
11276   if (CLUTTER_ACTOR_IS_MAPPED (child))
11277     clutter_actor_queue_redraw (child);
11278
11279   /* maintain the invariant that if an actor needs layout,
11280    * its parents do as well
11281    */
11282   if (child->priv->needs_width_request ||
11283       child->priv->needs_height_request ||
11284       child->priv->needs_allocation)
11285     {
11286       /* we work around the short-circuiting we do
11287        * in clutter_actor_queue_relayout() since we
11288        * want to force a relayout
11289        */
11290       child->priv->needs_width_request = TRUE;
11291       child->priv->needs_height_request = TRUE;
11292       child->priv->needs_allocation = TRUE;
11293
11294       clutter_actor_queue_relayout (child->priv->parent);
11295     }
11296
11297   if (emit_actor_added)
11298     g_signal_emit_by_name (self, "actor-added", child);
11299
11300   if (notify_first_last)
11301     {
11302       if (old_first_child != self->priv->first_child)
11303         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11304
11305       if (old_last_child != self->priv->last_child)
11306         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11307     }
11308
11309   g_object_thaw_notify (G_OBJECT (self));
11310 }
11311
11312 /**
11313  * clutter_actor_add_child:
11314  * @self: a #ClutterActor
11315  * @child: a #ClutterActor
11316  *
11317  * Adds @child to the children of @self.
11318  *
11319  * This function will acquire a reference on @child that will only
11320  * be released when calling clutter_actor_remove_child().
11321  *
11322  * This function will take into consideration the #ClutterActor:depth
11323  * of @child, and will keep the list of children sorted.
11324  *
11325  * This function will emit the #ClutterContainer::actor-added signal
11326  * on @self.
11327  *
11328  * Since: 1.10
11329  */
11330 void
11331 clutter_actor_add_child (ClutterActor *self,
11332                          ClutterActor *child)
11333 {
11334   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11335   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11336   g_return_if_fail (self != child);
11337   g_return_if_fail (child->priv->parent == NULL);
11338
11339   clutter_actor_add_child_internal (self, child,
11340                                     ADD_CHILD_DEFAULT_FLAGS,
11341                                     insert_child_at_depth,
11342                                     NULL);
11343 }
11344
11345 /**
11346  * clutter_actor_insert_child_at_index:
11347  * @self: a #ClutterActor
11348  * @child: a #ClutterActor
11349  * @index_: the index
11350  *
11351  * Inserts @child into the list of children of @self, using the
11352  * given @index_. If @index_ is greater than the number of children
11353  * in @self, or is less than 0, then the new child is added at the end.
11354  *
11355  * This function will acquire a reference on @child that will only
11356  * be released when calling clutter_actor_remove_child().
11357  *
11358  * This function will not take into consideration the #ClutterActor:depth
11359  * of @child.
11360  *
11361  * This function will emit the #ClutterContainer::actor-added signal
11362  * on @self.
11363  *
11364  * Since: 1.10
11365  */
11366 void
11367 clutter_actor_insert_child_at_index (ClutterActor *self,
11368                                      ClutterActor *child,
11369                                      gint          index_)
11370 {
11371   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11372   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11373   g_return_if_fail (self != child);
11374   g_return_if_fail (child->priv->parent == NULL);
11375
11376   clutter_actor_add_child_internal (self, child,
11377                                     ADD_CHILD_DEFAULT_FLAGS,
11378                                     insert_child_at_index,
11379                                     GINT_TO_POINTER (index_));
11380 }
11381
11382 /**
11383  * clutter_actor_insert_child_above:
11384  * @self: a #ClutterActor
11385  * @child: a #ClutterActor
11386  * @sibling: (allow-none): a child of @self, or %NULL
11387  *
11388  * Inserts @child into the list of children of @self, above another
11389  * child of @self or, if @sibling is %NULL, above all the children
11390  * of @self.
11391  *
11392  * This function will acquire a reference on @child that will only
11393  * be released when calling clutter_actor_remove_child().
11394  *
11395  * This function will not take into consideration the #ClutterActor:depth
11396  * of @child.
11397  *
11398  * This function will emit the #ClutterContainer::actor-added signal
11399  * on @self.
11400  *
11401  * Since: 1.10
11402  */
11403 void
11404 clutter_actor_insert_child_above (ClutterActor *self,
11405                                   ClutterActor *child,
11406                                   ClutterActor *sibling)
11407 {
11408   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11409   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11410   g_return_if_fail (self != child);
11411   g_return_if_fail (child != sibling);
11412   g_return_if_fail (child->priv->parent == NULL);
11413   g_return_if_fail (sibling == NULL ||
11414                     (CLUTTER_IS_ACTOR (sibling) &&
11415                      sibling->priv->parent == self));
11416
11417   clutter_actor_add_child_internal (self, child,
11418                                     ADD_CHILD_DEFAULT_FLAGS,
11419                                     insert_child_above,
11420                                     sibling);
11421 }
11422
11423 /**
11424  * clutter_actor_insert_child_below:
11425  * @self: a #ClutterActor
11426  * @child: a #ClutterActor
11427  * @sibling: (allow-none): a child of @self, or %NULL
11428  *
11429  * Inserts @child into the list of children of @self, below another
11430  * child of @self or, if @sibling is %NULL, below all the children
11431  * of @self.
11432  *
11433  * This function will acquire a reference on @child that will only
11434  * be released when calling clutter_actor_remove_child().
11435  *
11436  * This function will not take into consideration the #ClutterActor:depth
11437  * of @child.
11438  *
11439  * This function will emit the #ClutterContainer::actor-added signal
11440  * on @self.
11441  *
11442  * Since: 1.10
11443  */
11444 void
11445 clutter_actor_insert_child_below (ClutterActor *self,
11446                                   ClutterActor *child,
11447                                   ClutterActor *sibling)
11448 {
11449   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11450   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11451   g_return_if_fail (self != child);
11452   g_return_if_fail (child != sibling);
11453   g_return_if_fail (child->priv->parent == NULL);
11454   g_return_if_fail (sibling == NULL ||
11455                     (CLUTTER_IS_ACTOR (sibling) &&
11456                      sibling->priv->parent == self));
11457
11458   clutter_actor_add_child_internal (self, child,
11459                                     ADD_CHILD_DEFAULT_FLAGS,
11460                                     insert_child_below,
11461                                     sibling);
11462 }
11463
11464 /**
11465  * clutter_actor_set_parent:
11466  * @self: A #ClutterActor
11467  * @parent: A new #ClutterActor parent
11468  *
11469  * Sets the parent of @self to @parent.
11470  *
11471  * This function will result in @parent acquiring a reference on @self,
11472  * eventually by sinking its floating reference first. The reference
11473  * will be released by clutter_actor_unparent().
11474  *
11475  * This function should only be called by legacy #ClutterActor<!-- -->s
11476  * implementing the #ClutterContainer interface.
11477  *
11478  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11479  */
11480 void
11481 clutter_actor_set_parent (ClutterActor *self,
11482                           ClutterActor *parent)
11483 {
11484   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11485   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11486   g_return_if_fail (self != parent);
11487   g_return_if_fail (self->priv->parent == NULL);
11488
11489   /* as this function will be called inside ClutterContainer::add
11490    * implementations or when building up a composite actor, we have
11491    * to preserve the old behaviour, and not create child meta or
11492    * emit the ::actor-added signal, to avoid recursion or double
11493    * emissions
11494    */
11495   clutter_actor_add_child_internal (parent, self,
11496                                     ADD_CHILD_LEGACY_FLAGS,
11497                                     insert_child_at_depth,
11498                                     NULL);
11499 }
11500
11501 /**
11502  * clutter_actor_get_parent:
11503  * @self: A #ClutterActor
11504  *
11505  * Retrieves the parent of @self.
11506  *
11507  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11508  *  if no parent is set
11509  */
11510 ClutterActor *
11511 clutter_actor_get_parent (ClutterActor *self)
11512 {
11513   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11514
11515   return self->priv->parent;
11516 }
11517
11518 /**
11519  * clutter_actor_get_paint_visibility:
11520  * @self: A #ClutterActor
11521  *
11522  * Retrieves the 'paint' visibility of an actor recursively checking for non
11523  * visible parents.
11524  *
11525  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11526  *
11527  * Return Value: %TRUE if the actor is visibile and will be painted.
11528  *
11529  * Since: 0.8.4
11530  */
11531 gboolean
11532 clutter_actor_get_paint_visibility (ClutterActor *actor)
11533 {
11534   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11535
11536   return CLUTTER_ACTOR_IS_MAPPED (actor);
11537 }
11538
11539 /**
11540  * clutter_actor_remove_child:
11541  * @self: a #ClutterActor
11542  * @child: a #ClutterActor
11543  *
11544  * Removes @child from the children of @self.
11545  *
11546  * This function will release the reference added by
11547  * clutter_actor_add_child(), so if you want to keep using @child
11548  * you will have to acquire a referenced on it before calling this
11549  * function.
11550  *
11551  * This function will emit the #ClutterContainer::actor-removed
11552  * signal on @self.
11553  *
11554  * Since: 1.10
11555  */
11556 void
11557 clutter_actor_remove_child (ClutterActor *self,
11558                             ClutterActor *child)
11559 {
11560   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11561   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11562   g_return_if_fail (self != child);
11563   g_return_if_fail (child->priv->parent != NULL);
11564   g_return_if_fail (child->priv->parent == self);
11565
11566   clutter_actor_remove_child_internal (self, child,
11567                                        REMOVE_CHILD_DEFAULT_FLAGS);
11568 }
11569
11570 /**
11571  * clutter_actor_remove_all_children:
11572  * @self: a #ClutterActor
11573  *
11574  * Removes all children of @self.
11575  *
11576  * This function releases the reference added by inserting a child actor
11577  * in the list of children of @self.
11578  *
11579  * If the reference count of a child drops to zero, the child will be
11580  * destroyed. If you want to ensure the destruction of all the children
11581  * of @self, use clutter_actor_destroy_all_children().
11582  *
11583  * Since: 1.10
11584  */
11585 void
11586 clutter_actor_remove_all_children (ClutterActor *self)
11587 {
11588   ClutterActorIter iter;
11589
11590   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11591
11592   if (self->priv->n_children == 0)
11593     return;
11594
11595   g_object_freeze_notify (G_OBJECT (self));
11596
11597   clutter_actor_iter_init (&iter, self);
11598   while (clutter_actor_iter_next (&iter, NULL))
11599     clutter_actor_iter_remove (&iter);
11600
11601   g_object_thaw_notify (G_OBJECT (self));
11602
11603   /* sanity check */
11604   g_assert (self->priv->first_child == NULL);
11605   g_assert (self->priv->last_child == NULL);
11606   g_assert (self->priv->n_children == 0);
11607 }
11608
11609 /**
11610  * clutter_actor_destroy_all_children:
11611  * @self: a #ClutterActor
11612  *
11613  * Destroys all children of @self.
11614  *
11615  * This function releases the reference added by inserting a child
11616  * actor in the list of children of @self, and ensures that the
11617  * #ClutterActor::destroy signal is emitted on each child of the
11618  * actor.
11619  *
11620  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11621  * when its reference count drops to 0; the default handler of the
11622  * #ClutterActor::destroy signal will destroy all the children of an
11623  * actor. This function ensures that all children are destroyed, instead
11624  * of just removed from @self, unlike clutter_actor_remove_all_children()
11625  * which will merely release the reference and remove each child.
11626  *
11627  * Unless you acquired an additional reference on each child of @self
11628  * prior to calling clutter_actor_remove_all_children() and want to reuse
11629  * the actors, you should use clutter_actor_destroy_all_children() in
11630  * order to make sure that children are destroyed and signal handlers
11631  * are disconnected even in cases where circular references prevent this
11632  * from automatically happening through reference counting alone.
11633  *
11634  * Since: 1.10
11635  */
11636 void
11637 clutter_actor_destroy_all_children (ClutterActor *self)
11638 {
11639   ClutterActorIter iter;
11640
11641   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11642
11643   if (self->priv->n_children == 0)
11644     return;
11645
11646   g_object_freeze_notify (G_OBJECT (self));
11647
11648   clutter_actor_iter_init (&iter, self);
11649   while (clutter_actor_iter_next (&iter, NULL))
11650     clutter_actor_iter_destroy (&iter);
11651
11652   g_object_thaw_notify (G_OBJECT (self));
11653
11654   /* sanity check */
11655   g_assert (self->priv->first_child == NULL);
11656   g_assert (self->priv->last_child == NULL);
11657   g_assert (self->priv->n_children == 0);
11658 }
11659
11660 typedef struct _InsertBetweenData {
11661   ClutterActor *prev_sibling;
11662   ClutterActor *next_sibling;
11663 } InsertBetweenData;
11664
11665 static void
11666 insert_child_between (ClutterActor *self,
11667                       ClutterActor *child,
11668                       gpointer      data_)
11669 {
11670   InsertBetweenData *data = data_;
11671   ClutterActor *prev_sibling = data->prev_sibling;
11672   ClutterActor *next_sibling = data->next_sibling;
11673
11674   child->priv->parent = self;
11675   child->priv->prev_sibling = prev_sibling;
11676   child->priv->next_sibling = next_sibling;
11677
11678   if (prev_sibling != NULL)
11679     prev_sibling->priv->next_sibling = child;
11680
11681   if (next_sibling != NULL)
11682     next_sibling->priv->prev_sibling = child;
11683
11684   if (child->priv->prev_sibling == NULL)
11685     self->priv->first_child = child;
11686
11687   if (child->priv->next_sibling == NULL)
11688     self->priv->last_child = child;
11689 }
11690
11691 /**
11692  * clutter_actor_replace_child:
11693  * @self: a #ClutterActor
11694  * @old_child: the child of @self to replace
11695  * @new_child: the #ClutterActor to replace @old_child
11696  *
11697  * Replaces @old_child with @new_child in the list of children of @self.
11698  *
11699  * Since: 1.10
11700  */
11701 void
11702 clutter_actor_replace_child (ClutterActor *self,
11703                              ClutterActor *old_child,
11704                              ClutterActor *new_child)
11705 {
11706   ClutterActor *prev_sibling, *next_sibling;
11707   InsertBetweenData clos;
11708
11709   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11710   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11711   g_return_if_fail (old_child->priv->parent == self);
11712   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11713   g_return_if_fail (old_child != new_child);
11714   g_return_if_fail (new_child != self);
11715   g_return_if_fail (new_child->priv->parent == NULL);
11716
11717   prev_sibling = old_child->priv->prev_sibling;
11718   next_sibling = old_child->priv->next_sibling;
11719   clutter_actor_remove_child_internal (self, old_child,
11720                                        REMOVE_CHILD_DEFAULT_FLAGS);
11721
11722   clos.prev_sibling = prev_sibling;
11723   clos.next_sibling = next_sibling;
11724   clutter_actor_add_child_internal (self, new_child,
11725                                     ADD_CHILD_DEFAULT_FLAGS,
11726                                     insert_child_between,
11727                                     &clos);
11728 }
11729
11730 /**
11731  * clutter_actor_unparent:
11732  * @self: a #ClutterActor
11733  *
11734  * Removes the parent of @self.
11735  *
11736  * This will cause the parent of @self to release the reference
11737  * acquired when calling clutter_actor_set_parent(), so if you
11738  * want to keep @self you will have to acquire a reference of
11739  * your own, through g_object_ref().
11740  *
11741  * This function should only be called by legacy #ClutterActor<!-- -->s
11742  * implementing the #ClutterContainer interface.
11743  *
11744  * Since: 0.1.1
11745  *
11746  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11747  */
11748 void
11749 clutter_actor_unparent (ClutterActor *self)
11750 {
11751   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11752
11753   if (self->priv->parent == NULL)
11754     return;
11755
11756   clutter_actor_remove_child_internal (self->priv->parent, self,
11757                                        REMOVE_CHILD_LEGACY_FLAGS);
11758 }
11759
11760 /**
11761  * clutter_actor_reparent:
11762  * @self: a #ClutterActor
11763  * @new_parent: the new #ClutterActor parent
11764  *
11765  * Resets the parent actor of @self.
11766  *
11767  * This function is logically equivalent to calling clutter_actor_unparent()
11768  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11769  * ensures the child is not finalized when unparented, and emits the
11770  * #ClutterActor::parent-set signal only once.
11771  *
11772  * In reality, calling this function is less useful than it sounds, as some
11773  * application code may rely on changes in the intermediate state between
11774  * removal and addition of the actor from its old parent to the @new_parent.
11775  * Thus, it is strongly encouraged to avoid using this function in application
11776  * code.
11777  *
11778  * Since: 0.2
11779  *
11780  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11781  *   clutter_actor_add_child() instead; remember to take a reference on
11782  *   the actor being removed before calling clutter_actor_remove_child()
11783  *   to avoid the reference count dropping to zero and the actor being
11784  *   destroyed.
11785  */
11786 void
11787 clutter_actor_reparent (ClutterActor *self,
11788                         ClutterActor *new_parent)
11789 {
11790   ClutterActorPrivate *priv;
11791
11792   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11793   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11794   g_return_if_fail (self != new_parent);
11795
11796   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11797     {
11798       g_warning ("Cannot set a parent on a toplevel actor");
11799       return;
11800     }
11801
11802   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11803     {
11804       g_warning ("Cannot set a parent currently being destroyed");
11805       return;
11806     }
11807
11808   priv = self->priv;
11809
11810   if (priv->parent != new_parent)
11811     {
11812       ClutterActor *old_parent;
11813
11814       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11815
11816       old_parent = priv->parent;
11817
11818       g_object_ref (self);
11819
11820       if (old_parent != NULL)
11821         {
11822          /* go through the Container implementation if this is a regular
11823           * child and not an internal one
11824           */
11825          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11826            {
11827              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11828
11829              /* this will have to call unparent() */
11830              clutter_container_remove_actor (parent, self);
11831            }
11832          else
11833            clutter_actor_remove_child_internal (old_parent, self,
11834                                                 REMOVE_CHILD_LEGACY_FLAGS);
11835         }
11836
11837       /* Note, will call set_parent() */
11838       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11839         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11840       else
11841         clutter_actor_add_child_internal (new_parent, self,
11842                                           ADD_CHILD_LEGACY_FLAGS,
11843                                           insert_child_at_depth,
11844                                           NULL);
11845
11846       /* we emit the ::parent-set signal once */
11847       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11848
11849       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11850
11851       /* the IN_REPARENT flag suspends state updates */
11852       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11853
11854       g_object_unref (self);
11855    }
11856 }
11857
11858 /**
11859  * clutter_actor_contains:
11860  * @self: A #ClutterActor
11861  * @descendant: A #ClutterActor, possibly contained in @self
11862  *
11863  * Determines if @descendant is contained inside @self (either as an
11864  * immediate child, or as a deeper descendant). If @self and
11865  * @descendant point to the same actor then it will also return %TRUE.
11866  *
11867  * Return value: whether @descendent is contained within @self
11868  *
11869  * Since: 1.4
11870  */
11871 gboolean
11872 clutter_actor_contains (ClutterActor *self,
11873                         ClutterActor *descendant)
11874 {
11875   ClutterActor *actor;
11876
11877   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11878   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11879
11880   for (actor = descendant; actor; actor = actor->priv->parent)
11881     if (actor == self)
11882       return TRUE;
11883
11884   return FALSE;
11885 }
11886
11887 /**
11888  * clutter_actor_set_child_above_sibling:
11889  * @self: a #ClutterActor
11890  * @child: a #ClutterActor child of @self
11891  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11892  *
11893  * Sets @child to be above @sibling in the list of children of @self.
11894  *
11895  * If @sibling is %NULL, @child will be the new last child of @self.
11896  *
11897  * This function is logically equivalent to removing @child and using
11898  * clutter_actor_insert_child_above(), but it will not emit signals
11899  * or change state on @child.
11900  *
11901  * Since: 1.10
11902  */
11903 void
11904 clutter_actor_set_child_above_sibling (ClutterActor *self,
11905                                        ClutterActor *child,
11906                                        ClutterActor *sibling)
11907 {
11908   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11909   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11910   g_return_if_fail (child->priv->parent == self);
11911   g_return_if_fail (child != sibling);
11912   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11913
11914   if (sibling != NULL)
11915     g_return_if_fail (sibling->priv->parent == self);
11916
11917   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11918       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11919       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11920     return;
11921
11922   /* we don't want to change the state of child, or emit signals, or
11923    * regenerate ChildMeta instances here, but we still want to follow
11924    * the correct sequence of steps encoded in remove_child() and
11925    * add_child(), so that correctness is ensured, and we only go
11926    * through one known code path.
11927    */
11928   g_object_ref (child);
11929   clutter_actor_remove_child_internal (self, child, 0);
11930   clutter_actor_add_child_internal (self, child,
11931                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11932                                     insert_child_above,
11933                                     sibling);
11934
11935   clutter_actor_queue_relayout (self);
11936 }
11937
11938 /**
11939  * clutter_actor_set_child_below_sibling:
11940  * @self: a #ClutterActor
11941  * @child: a #ClutterActor child of @self
11942  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11943  *
11944  * Sets @child to be below @sibling in the list of children of @self.
11945  *
11946  * If @sibling is %NULL, @child will be the new first child of @self.
11947  *
11948  * This function is logically equivalent to removing @self and using
11949  * clutter_actor_insert_child_below(), but it will not emit signals
11950  * or change state on @child.
11951  *
11952  * Since: 1.10
11953  */
11954 void
11955 clutter_actor_set_child_below_sibling (ClutterActor *self,
11956                                        ClutterActor *child,
11957                                        ClutterActor *sibling)
11958 {
11959   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11960   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11961   g_return_if_fail (child->priv->parent == self);
11962   g_return_if_fail (child != sibling);
11963   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11964
11965   if (sibling != NULL)
11966     g_return_if_fail (sibling->priv->parent == self);
11967
11968   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11969       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11970       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11971     return;
11972
11973   /* see the comment in set_child_above_sibling() */
11974   g_object_ref (child);
11975   clutter_actor_remove_child_internal (self, child, 0);
11976   clutter_actor_add_child_internal (self, child,
11977                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11978                                     insert_child_below,
11979                                     sibling);
11980
11981   clutter_actor_queue_relayout (self);
11982 }
11983
11984 /**
11985  * clutter_actor_set_child_at_index:
11986  * @self: a #ClutterActor
11987  * @child: a #ClutterActor child of @self
11988  * @index_: the new index for @child
11989  *
11990  * Changes the index of @child in the list of children of @self.
11991  *
11992  * This function is logically equivalent to removing @child and
11993  * calling clutter_actor_insert_child_at_index(), but it will not
11994  * emit signals or change state on @child.
11995  *
11996  * Since: 1.10
11997  */
11998 void
11999 clutter_actor_set_child_at_index (ClutterActor *self,
12000                                   ClutterActor *child,
12001                                   gint          index_)
12002 {
12003   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12004   g_return_if_fail (CLUTTER_IS_ACTOR (child));
12005   g_return_if_fail (child->priv->parent == self);
12006   g_return_if_fail (index_ <= self->priv->n_children);
12007
12008   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
12009       CLUTTER_ACTOR_IN_DESTRUCTION (child))
12010     return;
12011
12012   g_object_ref (child);
12013   clutter_actor_remove_child_internal (self, child, 0);
12014   clutter_actor_add_child_internal (self, child,
12015                                     ADD_CHILD_NOTIFY_FIRST_LAST,
12016                                     insert_child_at_index,
12017                                     GINT_TO_POINTER (index_));
12018
12019   clutter_actor_queue_relayout (self);
12020 }
12021
12022 /**
12023  * clutter_actor_raise:
12024  * @self: A #ClutterActor
12025  * @below: (allow-none): A #ClutterActor to raise above.
12026  *
12027  * Puts @self above @below.
12028  *
12029  * Both actors must have the same parent, and the parent must implement
12030  * the #ClutterContainer interface
12031  *
12032  * This function calls clutter_container_raise_child() internally.
12033  *
12034  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
12035  */
12036 void
12037 clutter_actor_raise (ClutterActor *self,
12038                      ClutterActor *below)
12039 {
12040   ClutterActor *parent;
12041
12042   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12043
12044   parent = clutter_actor_get_parent (self);
12045   if (parent == NULL)
12046     {
12047       g_warning ("%s: Actor '%s' is not inside a container",
12048                  G_STRFUNC,
12049                  _clutter_actor_get_debug_name (self));
12050       return;
12051     }
12052
12053   if (below != NULL)
12054     {
12055       if (parent != clutter_actor_get_parent (below))
12056         {
12057           g_warning ("%s Actor '%s' is not in the same container as "
12058                      "actor '%s'",
12059                      G_STRFUNC,
12060                      _clutter_actor_get_debug_name (self),
12061                      _clutter_actor_get_debug_name (below));
12062           return;
12063         }
12064     }
12065
12066   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
12067 }
12068
12069 /**
12070  * clutter_actor_lower:
12071  * @self: A #ClutterActor
12072  * @above: (allow-none): A #ClutterActor to lower below
12073  *
12074  * Puts @self below @above.
12075  *
12076  * Both actors must have the same parent, and the parent must implement
12077  * the #ClutterContainer interface.
12078  *
12079  * This function calls clutter_container_lower_child() internally.
12080  *
12081  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
12082  */
12083 void
12084 clutter_actor_lower (ClutterActor *self,
12085                      ClutterActor *above)
12086 {
12087   ClutterActor *parent;
12088
12089   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12090
12091   parent = clutter_actor_get_parent (self);
12092   if (parent == NULL)
12093     {
12094       g_warning ("%s: Actor of type %s is not inside a container",
12095                  G_STRFUNC,
12096                  _clutter_actor_get_debug_name (self));
12097       return;
12098     }
12099
12100   if (above)
12101     {
12102       if (parent != clutter_actor_get_parent (above))
12103         {
12104           g_warning ("%s: Actor '%s' is not in the same container as "
12105                      "actor '%s'",
12106                      G_STRFUNC,
12107                      _clutter_actor_get_debug_name (self),
12108                      _clutter_actor_get_debug_name (above));
12109           return;
12110         }
12111     }
12112
12113   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
12114 }
12115
12116 /**
12117  * clutter_actor_raise_top:
12118  * @self: A #ClutterActor
12119  *
12120  * Raises @self to the top.
12121  *
12122  * This function calls clutter_actor_raise() internally.
12123  *
12124  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
12125  *   a %NULL sibling, instead.
12126  */
12127 void
12128 clutter_actor_raise_top (ClutterActor *self)
12129 {
12130   clutter_actor_raise (self, NULL);
12131 }
12132
12133 /**
12134  * clutter_actor_lower_bottom:
12135  * @self: A #ClutterActor
12136  *
12137  * Lowers @self to the bottom.
12138  *
12139  * This function calls clutter_actor_lower() internally.
12140  *
12141  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
12142  *   a %NULL sibling, instead.
12143  */
12144 void
12145 clutter_actor_lower_bottom (ClutterActor *self)
12146 {
12147   clutter_actor_lower (self, NULL);
12148 }
12149
12150 /*
12151  * Event handling
12152  */
12153
12154 /**
12155  * clutter_actor_event:
12156  * @actor: a #ClutterActor
12157  * @event: a #ClutterEvent
12158  * @capture: TRUE if event in in capture phase, FALSE otherwise.
12159  *
12160  * This function is used to emit an event on the main stage.
12161  * You should rarely need to use this function, except for
12162  * synthetising events.
12163  *
12164  * Return value: the return value from the signal emission: %TRUE
12165  *   if the actor handled the event, or %FALSE if the event was
12166  *   not handled
12167  *
12168  * Since: 0.6
12169  */
12170 gboolean
12171 clutter_actor_event (ClutterActor *actor,
12172                      ClutterEvent *event,
12173                      gboolean      capture)
12174 {
12175   gboolean retval = FALSE;
12176   gint signal_num = -1;
12177
12178   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12179   g_return_val_if_fail (event != NULL, FALSE);
12180
12181   g_object_ref (actor);
12182
12183   if (capture)
12184     {
12185       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
12186                      event,
12187                      &retval);
12188       goto out;
12189     }
12190
12191   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
12192
12193   if (!retval)
12194     {
12195       switch (event->type)
12196         {
12197         case CLUTTER_NOTHING:
12198           break;
12199         case CLUTTER_BUTTON_PRESS:
12200           signal_num = BUTTON_PRESS_EVENT;
12201           break;
12202         case CLUTTER_BUTTON_RELEASE:
12203           signal_num = BUTTON_RELEASE_EVENT;
12204           break;
12205         case CLUTTER_SCROLL:
12206           signal_num = SCROLL_EVENT;
12207           break;
12208         case CLUTTER_KEY_PRESS:
12209           signal_num = KEY_PRESS_EVENT;
12210           break;
12211         case CLUTTER_KEY_RELEASE:
12212           signal_num = KEY_RELEASE_EVENT;
12213           break;
12214         case CLUTTER_MOTION:
12215           signal_num = MOTION_EVENT;
12216           break;
12217         case CLUTTER_ENTER:
12218           signal_num = ENTER_EVENT;
12219           break;
12220         case CLUTTER_LEAVE:
12221           signal_num = LEAVE_EVENT;
12222           break;
12223         case CLUTTER_DELETE:
12224         case CLUTTER_DESTROY_NOTIFY:
12225         case CLUTTER_CLIENT_MESSAGE:
12226         default:
12227           signal_num = -1;
12228           break;
12229         }
12230
12231       if (signal_num != -1)
12232         g_signal_emit (actor, actor_signals[signal_num], 0,
12233                        event, &retval);
12234     }
12235
12236 out:
12237   g_object_unref (actor);
12238
12239   return retval;
12240 }
12241
12242 /**
12243  * clutter_actor_set_reactive:
12244  * @actor: a #ClutterActor
12245  * @reactive: whether the actor should be reactive to events
12246  *
12247  * Sets @actor as reactive. Reactive actors will receive events.
12248  *
12249  * Since: 0.6
12250  */
12251 void
12252 clutter_actor_set_reactive (ClutterActor *actor,
12253                             gboolean      reactive)
12254 {
12255   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12256
12257   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12258     return;
12259
12260   if (reactive)
12261     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12262   else
12263     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12264
12265   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12266 }
12267
12268 /**
12269  * clutter_actor_get_reactive:
12270  * @actor: a #ClutterActor
12271  *
12272  * Checks whether @actor is marked as reactive.
12273  *
12274  * Return value: %TRUE if the actor is reactive
12275  *
12276  * Since: 0.6
12277  */
12278 gboolean
12279 clutter_actor_get_reactive (ClutterActor *actor)
12280 {
12281   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12282
12283   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12284 }
12285
12286 /**
12287  * clutter_actor_get_anchor_point:
12288  * @self: a #ClutterActor
12289  * @anchor_x: (out): return location for the X coordinate of the anchor point
12290  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12291  *
12292  * Gets the current anchor point of the @actor in pixels.
12293  *
12294  * Since: 0.6
12295  */
12296 void
12297 clutter_actor_get_anchor_point (ClutterActor *self,
12298                                 gfloat       *anchor_x,
12299                                 gfloat       *anchor_y)
12300 {
12301   const ClutterTransformInfo *info;
12302
12303   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12304
12305   info = _clutter_actor_get_transform_info_or_defaults (self);
12306   clutter_anchor_coord_get_units (self, &info->anchor,
12307                                   anchor_x,
12308                                   anchor_y,
12309                                   NULL);
12310 }
12311
12312 /**
12313  * clutter_actor_set_anchor_point:
12314  * @self: a #ClutterActor
12315  * @anchor_x: X coordinate of the anchor point
12316  * @anchor_y: Y coordinate of the anchor point
12317  *
12318  * Sets an anchor point for @self. The anchor point is a point in the
12319  * coordinate space of an actor to which the actor position within its
12320  * parent is relative; the default is (0, 0), i.e. the top-left corner
12321  * of the actor.
12322  *
12323  * Since: 0.6
12324  */
12325 void
12326 clutter_actor_set_anchor_point (ClutterActor *self,
12327                                 gfloat        anchor_x,
12328                                 gfloat        anchor_y)
12329 {
12330   ClutterTransformInfo *info;
12331   ClutterActorPrivate *priv;
12332   gboolean changed = FALSE;
12333   gfloat old_anchor_x, old_anchor_y;
12334   GObject *obj;
12335
12336   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12337
12338   obj = G_OBJECT (self);
12339   priv = self->priv;
12340   info = _clutter_actor_get_transform_info (self);
12341
12342   g_object_freeze_notify (obj);
12343
12344   clutter_anchor_coord_get_units (self, &info->anchor,
12345                                   &old_anchor_x,
12346                                   &old_anchor_y,
12347                                   NULL);
12348
12349   if (info->anchor.is_fractional)
12350     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12351
12352   if (old_anchor_x != anchor_x)
12353     {
12354       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12355       changed = TRUE;
12356     }
12357
12358   if (old_anchor_y != anchor_y)
12359     {
12360       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12361       changed = TRUE;
12362     }
12363
12364   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12365
12366   if (changed)
12367     {
12368       priv->transform_valid = FALSE;
12369       clutter_actor_queue_redraw (self);
12370     }
12371
12372   g_object_thaw_notify (obj);
12373 }
12374
12375 /**
12376  * clutter_actor_get_anchor_point_gravity:
12377  * @self: a #ClutterActor
12378  *
12379  * Retrieves the anchor position expressed as a #ClutterGravity. If
12380  * the anchor point was specified using pixels or units this will
12381  * return %CLUTTER_GRAVITY_NONE.
12382  *
12383  * Return value: the #ClutterGravity used by the anchor point
12384  *
12385  * Since: 1.0
12386  */
12387 ClutterGravity
12388 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12389 {
12390   const ClutterTransformInfo *info;
12391
12392   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12393
12394   info = _clutter_actor_get_transform_info_or_defaults (self);
12395
12396   return clutter_anchor_coord_get_gravity (&info->anchor);
12397 }
12398
12399 /**
12400  * clutter_actor_move_anchor_point:
12401  * @self: a #ClutterActor
12402  * @anchor_x: X coordinate of the anchor point
12403  * @anchor_y: Y coordinate of the anchor point
12404  *
12405  * Sets an anchor point for the actor, and adjusts the actor postion so that
12406  * the relative position of the actor toward its parent remains the same.
12407  *
12408  * Since: 0.6
12409  */
12410 void
12411 clutter_actor_move_anchor_point (ClutterActor *self,
12412                                  gfloat        anchor_x,
12413                                  gfloat        anchor_y)
12414 {
12415   gfloat old_anchor_x, old_anchor_y;
12416   const ClutterTransformInfo *info;
12417
12418   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12419
12420   info = _clutter_actor_get_transform_info (self);
12421   clutter_anchor_coord_get_units (self, &info->anchor,
12422                                   &old_anchor_x,
12423                                   &old_anchor_y,
12424                                   NULL);
12425
12426   g_object_freeze_notify (G_OBJECT (self));
12427
12428   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12429
12430   if (self->priv->position_set)
12431     clutter_actor_move_by (self,
12432                            anchor_x - old_anchor_x,
12433                            anchor_y - old_anchor_y);
12434
12435   g_object_thaw_notify (G_OBJECT (self));
12436 }
12437
12438 /**
12439  * clutter_actor_move_anchor_point_from_gravity:
12440  * @self: a #ClutterActor
12441  * @gravity: #ClutterGravity.
12442  *
12443  * Sets an anchor point on the actor based on the given gravity, adjusting the
12444  * actor postion so that its relative position within its parent remains
12445  * unchanged.
12446  *
12447  * Since version 1.0 the anchor point will be stored as a gravity so
12448  * that if the actor changes size then the anchor point will move. For
12449  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12450  * and later double the size of the actor, the anchor point will move
12451  * to the bottom right.
12452  *
12453  * Since: 0.6
12454  */
12455 void
12456 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12457                                               ClutterGravity  gravity)
12458 {
12459   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12460   const ClutterTransformInfo *info;
12461   ClutterActorPrivate *priv;
12462
12463   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12464
12465   priv = self->priv;
12466   info = _clutter_actor_get_transform_info (self);
12467
12468   g_object_freeze_notify (G_OBJECT (self));
12469
12470   clutter_anchor_coord_get_units (self, &info->anchor,
12471                                   &old_anchor_x,
12472                                   &old_anchor_y,
12473                                   NULL);
12474   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12475   clutter_anchor_coord_get_units (self, &info->anchor,
12476                                   &new_anchor_x,
12477                                   &new_anchor_y,
12478                                   NULL);
12479
12480   if (priv->position_set)
12481     clutter_actor_move_by (self,
12482                            new_anchor_x - old_anchor_x,
12483                            new_anchor_y - old_anchor_y);
12484
12485   g_object_thaw_notify (G_OBJECT (self));
12486 }
12487
12488 /**
12489  * clutter_actor_set_anchor_point_from_gravity:
12490  * @self: a #ClutterActor
12491  * @gravity: #ClutterGravity.
12492  *
12493  * Sets an anchor point on the actor, based on the given gravity (this is a
12494  * convenience function wrapping clutter_actor_set_anchor_point()).
12495  *
12496  * Since version 1.0 the anchor point will be stored as a gravity so
12497  * that if the actor changes size then the anchor point will move. For
12498  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12499  * and later double the size of the actor, the anchor point will move
12500  * to the bottom right.
12501  *
12502  * Since: 0.6
12503  */
12504 void
12505 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12506                                              ClutterGravity  gravity)
12507 {
12508   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12509
12510   if (gravity == CLUTTER_GRAVITY_NONE)
12511     clutter_actor_set_anchor_point (self, 0, 0);
12512   else
12513     {
12514       GObject *obj = G_OBJECT (self);
12515       ClutterTransformInfo *info;
12516
12517       g_object_freeze_notify (obj);
12518
12519       info = _clutter_actor_get_transform_info (self);
12520       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12521
12522       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12523       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12524       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12525
12526       self->priv->transform_valid = FALSE;
12527
12528       clutter_actor_queue_redraw (self);
12529
12530       g_object_thaw_notify (obj);
12531     }
12532 }
12533
12534 static void
12535 clutter_actor_store_content_box (ClutterActor *self,
12536                                  const ClutterActorBox *box)
12537 {
12538   if (box != NULL)
12539     {
12540       self->priv->content_box = *box;
12541       self->priv->content_box_valid = TRUE;
12542     }
12543   else
12544     self->priv->content_box_valid = FALSE;
12545
12546   clutter_actor_queue_redraw (self);
12547
12548   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12549 }
12550
12551 static void
12552 clutter_container_iface_init (ClutterContainerIface *iface)
12553 {
12554   /* we don't override anything, as ClutterContainer already has a default
12555    * implementation that we can use, and which calls into our own API.
12556    */
12557 }
12558
12559 typedef enum
12560 {
12561   PARSE_X,
12562   PARSE_Y,
12563   PARSE_WIDTH,
12564   PARSE_HEIGHT,
12565   PARSE_ANCHOR_X,
12566   PARSE_ANCHOR_Y
12567 } ParseDimension;
12568
12569 static gfloat
12570 parse_units (ClutterActor   *self,
12571              ParseDimension  dimension,
12572              JsonNode       *node)
12573 {
12574   GValue value = G_VALUE_INIT;
12575   gfloat retval = 0;
12576
12577   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12578     return 0;
12579
12580   json_node_get_value (node, &value);
12581
12582   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12583     {
12584       retval = (gfloat) g_value_get_int64 (&value);
12585     }
12586   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12587     {
12588       retval = g_value_get_double (&value);
12589     }
12590   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12591     {
12592       ClutterUnits units;
12593       gboolean res;
12594
12595       res = clutter_units_from_string (&units, g_value_get_string (&value));
12596       if (res)
12597         retval = clutter_units_to_pixels (&units);
12598       else
12599         {
12600           g_warning ("Invalid value '%s': integers, strings or floating point "
12601                      "values can be used for the x, y, width and height "
12602                      "properties. Valid modifiers for strings are 'px', 'mm', "
12603                      "'pt' and 'em'.",
12604                      g_value_get_string (&value));
12605           retval = 0;
12606         }
12607     }
12608   else
12609     {
12610       g_warning ("Invalid value of type '%s': integers, strings of floating "
12611                  "point values can be used for the x, y, width, height "
12612                  "anchor-x and anchor-y properties.",
12613                  g_type_name (G_VALUE_TYPE (&value)));
12614     }
12615
12616   g_value_unset (&value);
12617
12618   return retval;
12619 }
12620
12621 typedef struct {
12622   ClutterRotateAxis axis;
12623
12624   gdouble angle;
12625
12626   gfloat center_x;
12627   gfloat center_y;
12628   gfloat center_z;
12629 } RotationInfo;
12630
12631 static inline gboolean
12632 parse_rotation_array (ClutterActor *actor,
12633                       JsonArray    *array,
12634                       RotationInfo *info)
12635 {
12636   JsonNode *element;
12637
12638   if (json_array_get_length (array) != 2)
12639     return FALSE;
12640
12641   /* angle */
12642   element = json_array_get_element (array, 0);
12643   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12644     info->angle = json_node_get_double (element);
12645   else
12646     return FALSE;
12647
12648   /* center */
12649   element = json_array_get_element (array, 1);
12650   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12651     {
12652       JsonArray *center = json_node_get_array (element);
12653
12654       if (json_array_get_length (center) != 2)
12655         return FALSE;
12656
12657       switch (info->axis)
12658         {
12659         case CLUTTER_X_AXIS:
12660           info->center_y = parse_units (actor, PARSE_Y,
12661                                         json_array_get_element (center, 0));
12662           info->center_z = parse_units (actor, PARSE_Y,
12663                                         json_array_get_element (center, 1));
12664           return TRUE;
12665
12666         case CLUTTER_Y_AXIS:
12667           info->center_x = parse_units (actor, PARSE_X,
12668                                         json_array_get_element (center, 0));
12669           info->center_z = parse_units (actor, PARSE_X,
12670                                         json_array_get_element (center, 1));
12671           return TRUE;
12672
12673         case CLUTTER_Z_AXIS:
12674           info->center_x = parse_units (actor, PARSE_X,
12675                                         json_array_get_element (center, 0));
12676           info->center_y = parse_units (actor, PARSE_Y,
12677                                         json_array_get_element (center, 1));
12678           return TRUE;
12679         }
12680     }
12681
12682   return FALSE;
12683 }
12684
12685 static gboolean
12686 parse_rotation (ClutterActor *actor,
12687                 JsonNode     *node,
12688                 RotationInfo *info)
12689 {
12690   JsonArray *array;
12691   guint len, i;
12692   gboolean retval = FALSE;
12693
12694   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12695     {
12696       g_warning ("Invalid node of type '%s' found, expecting an array",
12697                  json_node_type_name (node));
12698       return FALSE;
12699     }
12700
12701   array = json_node_get_array (node);
12702   len = json_array_get_length (array);
12703
12704   for (i = 0; i < len; i++)
12705     {
12706       JsonNode *element = json_array_get_element (array, i);
12707       JsonObject *object;
12708       JsonNode *member;
12709
12710       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12711         {
12712           g_warning ("Invalid node of type '%s' found, expecting an object",
12713                      json_node_type_name (element));
12714           return FALSE;
12715         }
12716
12717       object = json_node_get_object (element);
12718
12719       if (json_object_has_member (object, "x-axis"))
12720         {
12721           member = json_object_get_member (object, "x-axis");
12722
12723           info->axis = CLUTTER_X_AXIS;
12724
12725           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12726             {
12727               info->angle = json_node_get_double (member);
12728               retval = TRUE;
12729             }
12730           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12731             retval = parse_rotation_array (actor,
12732                                            json_node_get_array (member),
12733                                            info);
12734           else
12735             retval = FALSE;
12736         }
12737       else if (json_object_has_member (object, "y-axis"))
12738         {
12739           member = json_object_get_member (object, "y-axis");
12740
12741           info->axis = CLUTTER_Y_AXIS;
12742
12743           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12744             {
12745               info->angle = json_node_get_double (member);
12746               retval = TRUE;
12747             }
12748           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12749             retval = parse_rotation_array (actor,
12750                                            json_node_get_array (member),
12751                                            info);
12752           else
12753             retval = FALSE;
12754         }
12755       else if (json_object_has_member (object, "z-axis"))
12756         {
12757           member = json_object_get_member (object, "z-axis");
12758
12759           info->axis = CLUTTER_Z_AXIS;
12760
12761           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12762             {
12763               info->angle = json_node_get_double (member);
12764               retval = TRUE;
12765             }
12766           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12767             retval = parse_rotation_array (actor,
12768                                            json_node_get_array (member),
12769                                            info);
12770           else
12771             retval = FALSE;
12772         }
12773     }
12774
12775   return retval;
12776 }
12777
12778 static GSList *
12779 parse_actor_metas (ClutterScript *script,
12780                    ClutterActor  *actor,
12781                    JsonNode      *node)
12782 {
12783   GList *elements, *l;
12784   GSList *retval = NULL;
12785
12786   if (!JSON_NODE_HOLDS_ARRAY (node))
12787     return NULL;
12788
12789   elements = json_array_get_elements (json_node_get_array (node));
12790
12791   for (l = elements; l != NULL; l = l->next)
12792     {
12793       JsonNode *element = l->data;
12794       const gchar *id_ = _clutter_script_get_id_from_node (element);
12795       GObject *meta;
12796
12797       if (id_ == NULL || *id_ == '\0')
12798         continue;
12799
12800       meta = clutter_script_get_object (script, id_);
12801       if (meta == NULL)
12802         continue;
12803
12804       retval = g_slist_prepend (retval, meta);
12805     }
12806
12807   g_list_free (elements);
12808
12809   return g_slist_reverse (retval);
12810 }
12811
12812 static GSList *
12813 parse_behaviours (ClutterScript *script,
12814                   ClutterActor  *actor,
12815                   JsonNode      *node)
12816 {
12817   GList *elements, *l;
12818   GSList *retval = NULL;
12819
12820   if (!JSON_NODE_HOLDS_ARRAY (node))
12821     return NULL;
12822
12823   elements = json_array_get_elements (json_node_get_array (node));
12824
12825   for (l = elements; l != NULL; l = l->next)
12826     {
12827       JsonNode *element = l->data;
12828       const gchar *id_ = _clutter_script_get_id_from_node (element);
12829       GObject *behaviour;
12830
12831       if (id_ == NULL || *id_ == '\0')
12832         continue;
12833
12834       behaviour = clutter_script_get_object (script, id_);
12835       if (behaviour == NULL)
12836         continue;
12837
12838       retval = g_slist_prepend (retval, behaviour);
12839     }
12840
12841   g_list_free (elements);
12842
12843   return g_slist_reverse (retval);
12844 }
12845
12846 static gboolean
12847 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12848                                  ClutterScript     *script,
12849                                  GValue            *value,
12850                                  const gchar       *name,
12851                                  JsonNode          *node)
12852 {
12853   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12854   gboolean retval = FALSE;
12855
12856   if ((name[0] == 'x' && name[1] == '\0') ||
12857       (name[0] == 'y' && name[1] == '\0') ||
12858       (strcmp (name, "width") == 0) ||
12859       (strcmp (name, "height") == 0) ||
12860       (strcmp (name, "anchor_x") == 0) ||
12861       (strcmp (name, "anchor_y") == 0))
12862     {
12863       ParseDimension dimension;
12864       gfloat units;
12865
12866       if (name[0] == 'x')
12867         dimension = PARSE_X;
12868       else if (name[0] == 'y')
12869         dimension = PARSE_Y;
12870       else if (name[0] == 'w')
12871         dimension = PARSE_WIDTH;
12872       else if (name[0] == 'h')
12873         dimension = PARSE_HEIGHT;
12874       else if (name[0] == 'a' && name[7] == 'x')
12875         dimension = PARSE_ANCHOR_X;
12876       else if (name[0] == 'a' && name[7] == 'y')
12877         dimension = PARSE_ANCHOR_Y;
12878       else
12879         return FALSE;
12880
12881       units = parse_units (actor, dimension, node);
12882
12883       /* convert back to pixels: all properties are pixel-based */
12884       g_value_init (value, G_TYPE_FLOAT);
12885       g_value_set_float (value, units);
12886
12887       retval = TRUE;
12888     }
12889   else if (strcmp (name, "rotation") == 0)
12890     {
12891       RotationInfo *info;
12892
12893       info = g_slice_new0 (RotationInfo);
12894       retval = parse_rotation (actor, node, info);
12895
12896       if (retval)
12897         {
12898           g_value_init (value, G_TYPE_POINTER);
12899           g_value_set_pointer (value, info);
12900         }
12901       else
12902         g_slice_free (RotationInfo, info);
12903     }
12904   else if (strcmp (name, "behaviours") == 0)
12905     {
12906       GSList *l;
12907
12908 #ifdef CLUTTER_ENABLE_DEBUG
12909       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12910         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12911                                      "and it should not be used in newly "
12912                                      "written ClutterScript definitions.");
12913 #endif
12914
12915       l = parse_behaviours (script, actor, node);
12916
12917       g_value_init (value, G_TYPE_POINTER);
12918       g_value_set_pointer (value, l);
12919
12920       retval = TRUE;
12921     }
12922   else if (strcmp (name, "actions") == 0 ||
12923            strcmp (name, "constraints") == 0 ||
12924            strcmp (name, "effects") == 0)
12925     {
12926       GSList *l;
12927
12928       l = parse_actor_metas (script, actor, node);
12929
12930       g_value_init (value, G_TYPE_POINTER);
12931       g_value_set_pointer (value, l);
12932
12933       retval = TRUE;
12934     }
12935
12936   return retval;
12937 }
12938
12939 static void
12940 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12941                                    ClutterScript     *script,
12942                                    const gchar       *name,
12943                                    const GValue      *value)
12944 {
12945   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12946
12947 #ifdef CLUTTER_ENABLE_DEBUG
12948   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12949     {
12950       gchar *tmp = g_strdup_value_contents (value);
12951
12952       CLUTTER_NOTE (SCRIPT,
12953                     "in ClutterActor::set_custom_property('%s') = %s",
12954                     name,
12955                     tmp);
12956
12957       g_free (tmp);
12958     }
12959 #endif /* CLUTTER_ENABLE_DEBUG */
12960
12961   if (strcmp (name, "rotation") == 0)
12962     {
12963       RotationInfo *info;
12964
12965       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12966         return;
12967
12968       info = g_value_get_pointer (value);
12969
12970       clutter_actor_set_rotation (actor,
12971                                   info->axis, info->angle,
12972                                   info->center_x,
12973                                   info->center_y,
12974                                   info->center_z);
12975
12976       g_slice_free (RotationInfo, info);
12977
12978       return;
12979     }
12980
12981   if (strcmp (name, "behaviours") == 0)
12982     {
12983       GSList *behaviours, *l;
12984
12985       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12986         return;
12987
12988       behaviours = g_value_get_pointer (value);
12989       for (l = behaviours; l != NULL; l = l->next)
12990         {
12991           ClutterBehaviour *behaviour = l->data;
12992
12993           clutter_behaviour_apply (behaviour, actor);
12994         }
12995
12996       g_slist_free (behaviours);
12997
12998       return;
12999     }
13000
13001   if (strcmp (name, "actions") == 0 ||
13002       strcmp (name, "constraints") == 0 ||
13003       strcmp (name, "effects") == 0)
13004     {
13005       GSList *metas, *l;
13006
13007       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
13008         return;
13009
13010       metas = g_value_get_pointer (value);
13011       for (l = metas; l != NULL; l = l->next)
13012         {
13013           if (name[0] == 'a')
13014             clutter_actor_add_action (actor, l->data);
13015
13016           if (name[0] == 'c')
13017             clutter_actor_add_constraint (actor, l->data);
13018
13019           if (name[0] == 'e')
13020             clutter_actor_add_effect (actor, l->data);
13021         }
13022
13023       g_slist_free (metas);
13024
13025       return;
13026     }
13027
13028   g_object_set_property (G_OBJECT (scriptable), name, value);
13029 }
13030
13031 static void
13032 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
13033 {
13034   iface->parse_custom_node = clutter_actor_parse_custom_node;
13035   iface->set_custom_property = clutter_actor_set_custom_property;
13036 }
13037
13038 static ClutterActorMeta *
13039 get_meta_from_animation_property (ClutterActor  *actor,
13040                                   const gchar   *name,
13041                                   gchar        **name_p)
13042 {
13043   ClutterActorPrivate *priv = actor->priv;
13044   ClutterActorMeta *meta = NULL;
13045   gchar **tokens;
13046
13047   /* if this is not a special property, fall through */
13048   if (name[0] != '@')
13049     return NULL;
13050
13051   /* detect the properties named using the following spec:
13052    *
13053    *   @<section>.<meta-name>.<property-name>
13054    *
13055    * where <section> can be one of the following:
13056    *
13057    *   - actions
13058    *   - constraints
13059    *   - effects
13060    *
13061    * and <meta-name> is the name set on a specific ActorMeta
13062    */
13063
13064   tokens = g_strsplit (name + 1, ".", -1);
13065   if (tokens == NULL || g_strv_length (tokens) != 3)
13066     {
13067       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
13068                     name + 1);
13069       g_strfreev (tokens);
13070       return NULL;
13071     }
13072
13073   if (strcmp (tokens[0], "actions") == 0)
13074     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
13075
13076   if (strcmp (tokens[0], "constraints") == 0)
13077     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
13078
13079   if (strcmp (tokens[0], "effects") == 0)
13080     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
13081
13082   if (name_p != NULL)
13083     *name_p = g_strdup (tokens[2]);
13084
13085   CLUTTER_NOTE (ANIMATION,
13086                 "Looking for property '%s' of object '%s' in section '%s'",
13087                 tokens[2],
13088                 tokens[1],
13089                 tokens[0]);
13090
13091   g_strfreev (tokens);
13092
13093   return meta;
13094 }
13095
13096 static GParamSpec *
13097 clutter_actor_find_property (ClutterAnimatable *animatable,
13098                              const gchar       *property_name)
13099 {
13100   ClutterActorMeta *meta = NULL;
13101   GObjectClass *klass = NULL;
13102   GParamSpec *pspec = NULL;
13103   gchar *p_name = NULL;
13104
13105   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13106                                            property_name,
13107                                            &p_name);
13108
13109   if (meta != NULL)
13110     {
13111       klass = G_OBJECT_GET_CLASS (meta);
13112
13113       pspec = g_object_class_find_property (klass, p_name);
13114     }
13115   else
13116     {
13117       klass = G_OBJECT_GET_CLASS (animatable);
13118
13119       pspec = g_object_class_find_property (klass, property_name);
13120     }
13121
13122   g_free (p_name);
13123
13124   return pspec;
13125 }
13126
13127 static void
13128 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
13129                                  const gchar       *property_name,
13130                                  GValue            *initial)
13131 {
13132   ClutterActorMeta *meta = NULL;
13133   gchar *p_name = NULL;
13134
13135   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
13136                                            property_name,
13137                                            &p_name);
13138
13139   if (meta != NULL)
13140     g_object_get_property (G_OBJECT (meta), p_name, initial);
13141   else
13142     g_object_get_property (G_OBJECT (animatable), property_name, initial);
13143
13144   g_free (p_name);
13145 }
13146
13147 /*
13148  * clutter_actor_set_animatable_property:
13149  * @actor: a #ClutterActor
13150  * @prop_id: the paramspec id
13151  * @value: the value to set
13152  * @pspec: the paramspec
13153  *
13154  * Sets values of animatable properties.
13155  *
13156  * This is a variant of clutter_actor_set_property() that gets called
13157  * by the #ClutterAnimatable implementation of #ClutterActor for the
13158  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
13159  * #GParamSpec.
13160  *
13161  * Unlike the implementation of #GObjectClass.set_property(), this
13162  * function will not update the interval if a transition involving an
13163  * animatable property is in progress - this avoids cycles with the
13164  * transition API calling the public API.
13165  */
13166 static void
13167 clutter_actor_set_animatable_property (ClutterActor *actor,
13168                                        guint         prop_id,
13169                                        const GValue *value,
13170                                        GParamSpec   *pspec)
13171 {
13172   GObject *obj = G_OBJECT (actor);
13173
13174   g_object_freeze_notify (obj);
13175
13176   switch (prop_id)
13177     {
13178     case PROP_X:
13179       clutter_actor_set_x_internal (actor, g_value_get_float (value));
13180       break;
13181
13182     case PROP_Y:
13183       clutter_actor_set_y_internal (actor, g_value_get_float (value));
13184       break;
13185
13186     case PROP_POSITION:
13187       clutter_actor_set_position_internal (actor, g_value_get_boxed (value));
13188       break;
13189
13190     case PROP_WIDTH:
13191       clutter_actor_set_width_internal (actor, g_value_get_float (value));
13192       break;
13193
13194     case PROP_HEIGHT:
13195       clutter_actor_set_height_internal (actor, g_value_get_float (value));
13196       break;
13197
13198     case PROP_SIZE:
13199       clutter_actor_set_size_internal (actor, g_value_get_boxed (value));
13200       break;
13201
13202     case PROP_DEPTH:
13203       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
13204       break;
13205
13206     case PROP_OPACITY:
13207       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
13208       break;
13209
13210     case PROP_BACKGROUND_COLOR:
13211       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13212       break;
13213
13214     case PROP_SCALE_X:
13215       clutter_actor_set_scale_factor_internal (actor,
13216                                                g_value_get_double (value),
13217                                                pspec);
13218       break;
13219
13220     case PROP_SCALE_Y:
13221       clutter_actor_set_scale_factor_internal (actor,
13222                                                g_value_get_double (value),
13223                                                pspec);
13224       break;
13225
13226     case PROP_ROTATION_ANGLE_X:
13227       clutter_actor_set_rotation_angle_internal (actor,
13228                                                  CLUTTER_X_AXIS,
13229                                                  g_value_get_double (value));
13230       break;
13231
13232     case PROP_ROTATION_ANGLE_Y:
13233       clutter_actor_set_rotation_angle_internal (actor,
13234                                                  CLUTTER_Y_AXIS,
13235                                                  g_value_get_double (value));
13236       break;
13237
13238     case PROP_ROTATION_ANGLE_Z:
13239       clutter_actor_set_rotation_angle_internal (actor,
13240                                                  CLUTTER_Z_AXIS,
13241                                                  g_value_get_double (value));
13242       break;
13243
13244     case PROP_CONTENT_BOX:
13245       clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13246       break;
13247
13248     default:
13249       g_object_set_property (obj, pspec->name, value);
13250       break;
13251     }
13252
13253   g_object_thaw_notify (obj);
13254 }
13255
13256 static void
13257 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13258                                const gchar       *property_name,
13259                                const GValue      *final)
13260 {
13261   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13262   ClutterActorMeta *meta = NULL;
13263   gchar *p_name = NULL;
13264
13265   meta = get_meta_from_animation_property (actor,
13266                                            property_name,
13267                                            &p_name);
13268   if (meta != NULL)
13269     g_object_set_property (G_OBJECT (meta), p_name, final);
13270   else
13271     {
13272       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13273       GParamSpec *pspec;
13274
13275       pspec = g_object_class_find_property (obj_class, property_name);
13276
13277       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13278         {
13279           /* XXX - I'm going to the special hell for this */
13280           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13281         }
13282       else
13283         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13284     }
13285
13286   g_free (p_name);
13287 }
13288
13289 static void
13290 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13291 {
13292   iface->find_property = clutter_actor_find_property;
13293   iface->get_initial_state = clutter_actor_get_initial_state;
13294   iface->set_final_state = clutter_actor_set_final_state;
13295 }
13296
13297 /**
13298  * clutter_actor_transform_stage_point:
13299  * @self: A #ClutterActor
13300  * @x: (in): x screen coordinate of the point to unproject
13301  * @y: (in): y screen coordinate of the point to unproject
13302  * @x_out: (out): return location for the unprojected x coordinance
13303  * @y_out: (out): return location for the unprojected y coordinance
13304  *
13305  * This function translates screen coordinates (@x, @y) to
13306  * coordinates relative to the actor. For example, it can be used to translate
13307  * screen events from global screen coordinates into actor-local coordinates.
13308  *
13309  * The conversion can fail, notably if the transform stack results in the
13310  * actor being projected on the screen as a mere line.
13311  *
13312  * The conversion should not be expected to be pixel-perfect due to the
13313  * nature of the operation. In general the error grows when the skewing
13314  * of the actor rectangle on screen increases.
13315  *
13316  * <note><para>This function can be computationally intensive.</para></note>
13317  *
13318  * <note><para>This function only works when the allocation is up-to-date,
13319  * i.e. inside of paint().</para></note>
13320  *
13321  * Return value: %TRUE if conversion was successful.
13322  *
13323  * Since: 0.6
13324  */
13325 gboolean
13326 clutter_actor_transform_stage_point (ClutterActor *self,
13327                                      gfloat        x,
13328                                      gfloat        y,
13329                                      gfloat       *x_out,
13330                                      gfloat       *y_out)
13331 {
13332   ClutterVertex v[4];
13333   float ST[3][3];
13334   float RQ[3][3];
13335   int du, dv, xi, yi;
13336   float px, py;
13337   float xf, yf, wf, det;
13338   ClutterActorPrivate *priv;
13339
13340   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13341
13342   priv = self->priv;
13343
13344   /* This implementation is based on the quad -> quad projection algorithm
13345    * described by Paul Heckbert in:
13346    *
13347    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13348    *
13349    * and the sample implementation at:
13350    *
13351    *   http://www.cs.cmu.edu/~ph/src/texfund/
13352    *
13353    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13354    * quad to rectangle only, which significantly simplifies things; the
13355    * function calls have been unrolled, and most of the math is done in fixed
13356    * point.
13357    */
13358
13359   clutter_actor_get_abs_allocation_vertices (self, v);
13360
13361   /* Keeping these as ints simplifies the multiplication (no significant
13362    * loss of precision here).
13363    */
13364   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13365   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13366
13367   if (!du || !dv)
13368     return FALSE;
13369
13370 #define UX2FP(x)        (x)
13371 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13372
13373   /* First, find mapping from unit uv square to xy quadrilateral; this
13374    * equivalent to the pmap_square_quad() functions in the sample
13375    * implementation, which we can simplify, since our target is always
13376    * a rectangle.
13377    */
13378   px = v[0].x - v[1].x + v[3].x - v[2].x;
13379   py = v[0].y - v[1].y + v[3].y - v[2].y;
13380
13381   if (!px && !py)
13382     {
13383       /* affine transform */
13384       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13385       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13386       RQ[2][0] = UX2FP (v[0].x);
13387       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13388       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13389       RQ[2][1] = UX2FP (v[0].y);
13390       RQ[0][2] = 0;
13391       RQ[1][2] = 0;
13392       RQ[2][2] = 1.0;
13393     }
13394   else
13395     {
13396       /* projective transform */
13397       double dx1, dx2, dy1, dy2, del;
13398
13399       dx1 = UX2FP (v[1].x - v[3].x);
13400       dx2 = UX2FP (v[2].x - v[3].x);
13401       dy1 = UX2FP (v[1].y - v[3].y);
13402       dy2 = UX2FP (v[2].y - v[3].y);
13403
13404       del = DET2FP (dx1, dx2, dy1, dy2);
13405       if (!del)
13406         return FALSE;
13407
13408       /*
13409        * The division here needs to be done in floating point for
13410        * precisions reasons.
13411        */
13412       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13413       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13414       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13415       RQ[2][2] = 1.0;
13416       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13417       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13418       RQ[2][0] = UX2FP (v[0].x);
13419       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13420       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13421       RQ[2][1] = UX2FP (v[0].y);
13422     }
13423
13424   /*
13425    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13426    * square. Since our rectangle is based at 0,0 we only need to scale.
13427    */
13428   RQ[0][0] /= du;
13429   RQ[1][0] /= dv;
13430   RQ[0][1] /= du;
13431   RQ[1][1] /= dv;
13432   RQ[0][2] /= du;
13433   RQ[1][2] /= dv;
13434
13435   /*
13436    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13437    * inverse of that.
13438    */
13439   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13440   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13441   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13442   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13443   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13444   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13445   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13446   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13447   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13448
13449   /*
13450    * Check the resulting matrix is OK.
13451    */
13452   det = (RQ[0][0] * ST[0][0])
13453       + (RQ[0][1] * ST[0][1])
13454       + (RQ[0][2] * ST[0][2]);
13455   if (!det)
13456     return FALSE;
13457
13458   /*
13459    * Now transform our point with the ST matrix; the notional w
13460    * coordinate is 1, hence the last part is simply added.
13461    */
13462   xi = (int) x;
13463   yi = (int) y;
13464
13465   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13466   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13467   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13468
13469   if (x_out)
13470     *x_out = xf / wf;
13471
13472   if (y_out)
13473     *y_out = yf / wf;
13474
13475 #undef UX2FP
13476 #undef DET2FP
13477
13478   return TRUE;
13479 }
13480
13481 /**
13482  * clutter_actor_is_rotated:
13483  * @self: a #ClutterActor
13484  *
13485  * Checks whether any rotation is applied to the actor.
13486  *
13487  * Return value: %TRUE if the actor is rotated.
13488  *
13489  * Since: 0.6
13490  */
13491 gboolean
13492 clutter_actor_is_rotated (ClutterActor *self)
13493 {
13494   const ClutterTransformInfo *info;
13495
13496   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13497
13498   info = _clutter_actor_get_transform_info_or_defaults (self);
13499
13500   if (info->rx_angle || info->ry_angle || info->rz_angle)
13501     return TRUE;
13502
13503   return FALSE;
13504 }
13505
13506 /**
13507  * clutter_actor_is_scaled:
13508  * @self: a #ClutterActor
13509  *
13510  * Checks whether the actor is scaled in either dimension.
13511  *
13512  * Return value: %TRUE if the actor is scaled.
13513  *
13514  * Since: 0.6
13515  */
13516 gboolean
13517 clutter_actor_is_scaled (ClutterActor *self)
13518 {
13519   const ClutterTransformInfo *info;
13520
13521   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13522
13523   info = _clutter_actor_get_transform_info_or_defaults (self);
13524
13525   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13526     return TRUE;
13527
13528   return FALSE;
13529 }
13530
13531 ClutterActor *
13532 _clutter_actor_get_stage_internal (ClutterActor *actor)
13533 {
13534   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13535     actor = actor->priv->parent;
13536
13537   return actor;
13538 }
13539
13540 /**
13541  * clutter_actor_get_stage:
13542  * @actor: a #ClutterActor
13543  *
13544  * Retrieves the #ClutterStage where @actor is contained.
13545  *
13546  * Return value: (transfer none) (type Clutter.Stage): the stage
13547  *   containing the actor, or %NULL
13548  *
13549  * Since: 0.8
13550  */
13551 ClutterActor *
13552 clutter_actor_get_stage (ClutterActor *actor)
13553 {
13554   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13555
13556   return _clutter_actor_get_stage_internal (actor);
13557 }
13558
13559 /**
13560  * clutter_actor_allocate_available_size:
13561  * @self: a #ClutterActor
13562  * @x: the actor's X coordinate
13563  * @y: the actor's Y coordinate
13564  * @available_width: the maximum available width, or -1 to use the
13565  *   actor's natural width
13566  * @available_height: the maximum available height, or -1 to use the
13567  *   actor's natural height
13568  * @flags: flags controlling the allocation
13569  *
13570  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13571  * preferred size, but limiting it to the maximum available width
13572  * and height provided.
13573  *
13574  * This function will do the right thing when dealing with the
13575  * actor's request mode.
13576  *
13577  * The implementation of this function is equivalent to:
13578  *
13579  * |[
13580  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13581  *     {
13582  *       clutter_actor_get_preferred_width (self, available_height,
13583  *                                          &amp;min_width,
13584  *                                          &amp;natural_width);
13585  *       width = CLAMP (natural_width, min_width, available_width);
13586  *
13587  *       clutter_actor_get_preferred_height (self, width,
13588  *                                           &amp;min_height,
13589  *                                           &amp;natural_height);
13590  *       height = CLAMP (natural_height, min_height, available_height);
13591  *     }
13592  *   else
13593  *     {
13594  *       clutter_actor_get_preferred_height (self, available_width,
13595  *                                           &amp;min_height,
13596  *                                           &amp;natural_height);
13597  *       height = CLAMP (natural_height, min_height, available_height);
13598  *
13599  *       clutter_actor_get_preferred_width (self, height,
13600  *                                          &amp;min_width,
13601  *                                          &amp;natural_width);
13602  *       width = CLAMP (natural_width, min_width, available_width);
13603  *     }
13604  *
13605  *   box.x1 = x; box.y1 = y;
13606  *   box.x2 = box.x1 + available_width;
13607  *   box.y2 = box.y1 + available_height;
13608  *   clutter_actor_allocate (self, &amp;box, flags);
13609  * ]|
13610  *
13611  * This function can be used by fluid layout managers to allocate
13612  * an actor's preferred size without making it bigger than the area
13613  * available for the container.
13614  *
13615  * Since: 1.0
13616  */
13617 void
13618 clutter_actor_allocate_available_size (ClutterActor           *self,
13619                                        gfloat                  x,
13620                                        gfloat                  y,
13621                                        gfloat                  available_width,
13622                                        gfloat                  available_height,
13623                                        ClutterAllocationFlags  flags)
13624 {
13625   ClutterActorPrivate *priv;
13626   gfloat width, height;
13627   gfloat min_width, min_height;
13628   gfloat natural_width, natural_height;
13629   ClutterActorBox box;
13630
13631   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13632
13633   priv = self->priv;
13634
13635   width = height = 0.0;
13636
13637   switch (priv->request_mode)
13638     {
13639     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13640       clutter_actor_get_preferred_width (self, available_height,
13641                                          &min_width,
13642                                          &natural_width);
13643       width  = CLAMP (natural_width, min_width, available_width);
13644
13645       clutter_actor_get_preferred_height (self, width,
13646                                           &min_height,
13647                                           &natural_height);
13648       height = CLAMP (natural_height, min_height, available_height);
13649       break;
13650
13651     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13652       clutter_actor_get_preferred_height (self, available_width,
13653                                           &min_height,
13654                                           &natural_height);
13655       height = CLAMP (natural_height, min_height, available_height);
13656
13657       clutter_actor_get_preferred_width (self, height,
13658                                          &min_width,
13659                                          &natural_width);
13660       width  = CLAMP (natural_width, min_width, available_width);
13661       break;
13662     }
13663
13664
13665   box.x1 = x;
13666   box.y1 = y;
13667   box.x2 = box.x1 + width;
13668   box.y2 = box.y1 + height;
13669   clutter_actor_allocate (self, &box, flags);
13670 }
13671
13672 /**
13673  * clutter_actor_allocate_preferred_size:
13674  * @self: a #ClutterActor
13675  * @flags: flags controlling the allocation
13676  *
13677  * Allocates the natural size of @self.
13678  *
13679  * This function is a utility call for #ClutterActor implementations
13680  * that allocates the actor's preferred natural size. It can be used
13681  * by fixed layout managers (like #ClutterGroup or so called
13682  * 'composite actors') inside the ClutterActor::allocate
13683  * implementation to give each child exactly how much space it
13684  * requires.
13685  *
13686  * This function is not meant to be used by applications. It is also
13687  * not meant to be used outside the implementation of the
13688  * ClutterActor::allocate virtual function.
13689  *
13690  * Since: 0.8
13691  */
13692 void
13693 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13694                                        ClutterAllocationFlags  flags)
13695 {
13696   gfloat actor_x, actor_y;
13697   gfloat natural_width, natural_height;
13698   ClutterActorBox actor_box;
13699
13700   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13701
13702   actor_x = clutter_actor_get_x (self);
13703   actor_y = clutter_actor_get_y (self);
13704
13705   clutter_actor_get_preferred_size (self,
13706                                     NULL, NULL,
13707                                     &natural_width,
13708                                     &natural_height);
13709
13710   actor_box.x1 = actor_x;
13711   actor_box.y1 = actor_y;
13712   actor_box.x2 = actor_box.x1 + natural_width;
13713   actor_box.y2 = actor_box.y1 + natural_height;
13714
13715   clutter_actor_allocate (self, &actor_box, flags);
13716 }
13717
13718 /**
13719  * clutter_actor_allocate_align_fill:
13720  * @self: a #ClutterActor
13721  * @box: a #ClutterActorBox, containing the available width and height
13722  * @x_align: the horizontal alignment, between 0 and 1
13723  * @y_align: the vertical alignment, between 0 and 1
13724  * @x_fill: whether the actor should fill horizontally
13725  * @y_fill: whether the actor should fill vertically
13726  * @flags: allocation flags to be passed to clutter_actor_allocate()
13727  *
13728  * Allocates @self by taking into consideration the available allocation
13729  * area; an alignment factor on either axis; and whether the actor should
13730  * fill the allocation on either axis.
13731  *
13732  * The @box should contain the available allocation width and height;
13733  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13734  * allocation will be offset by their value.
13735  *
13736  * This function takes into consideration the geometry request specified by
13737  * the #ClutterActor:request-mode property, and the text direction.
13738  *
13739  * This function is useful for fluid layout managers, like #ClutterBinLayout
13740  * or #ClutterTableLayout
13741  *
13742  * Since: 1.4
13743  */
13744 void
13745 clutter_actor_allocate_align_fill (ClutterActor           *self,
13746                                    const ClutterActorBox  *box,
13747                                    gdouble                 x_align,
13748                                    gdouble                 y_align,
13749                                    gboolean                x_fill,
13750                                    gboolean                y_fill,
13751                                    ClutterAllocationFlags  flags)
13752 {
13753   ClutterActorPrivate *priv;
13754   ClutterActorBox allocation = { 0, };
13755   gfloat x_offset, y_offset;
13756   gfloat available_width, available_height;
13757   gfloat child_width, child_height;
13758
13759   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13760   g_return_if_fail (box != NULL);
13761   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13762   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13763
13764   priv = self->priv;
13765
13766   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13767   clutter_actor_box_get_size (box, &available_width, &available_height);
13768
13769   if (available_width < 0)
13770     available_width = 0;
13771
13772   if (available_height < 0)
13773     available_height = 0;
13774
13775   if (x_fill)
13776     {
13777       allocation.x1 = x_offset;
13778       allocation.x2 = allocation.x1 + available_width;
13779     }
13780
13781   if (y_fill)
13782     {
13783       allocation.y1 = y_offset;
13784       allocation.y2 = allocation.y1 + available_height;
13785     }
13786
13787   /* if we are filling horizontally and vertically then we're done */
13788   if (x_fill && y_fill)
13789     goto out;
13790
13791   child_width = child_height = 0.0f;
13792
13793   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13794     {
13795       gfloat min_width, natural_width;
13796       gfloat min_height, natural_height;
13797
13798       clutter_actor_get_preferred_width (self, available_height,
13799                                          &min_width,
13800                                          &natural_width);
13801
13802       child_width = CLAMP (natural_width, min_width, available_width);
13803
13804       if (!y_fill)
13805         {
13806           clutter_actor_get_preferred_height (self, child_width,
13807                                               &min_height,
13808                                               &natural_height);
13809
13810           child_height = CLAMP (natural_height, min_height, available_height);
13811         }
13812     }
13813   else
13814     {
13815       gfloat min_width, natural_width;
13816       gfloat min_height, natural_height;
13817
13818       clutter_actor_get_preferred_height (self, available_width,
13819                                           &min_height,
13820                                           &natural_height);
13821
13822       child_height = CLAMP (natural_height, min_height, available_height);
13823
13824       if (!x_fill)
13825         {
13826           clutter_actor_get_preferred_width (self, child_height,
13827                                              &min_width,
13828                                              &natural_width);
13829
13830           child_width = CLAMP (natural_width, min_width, available_width);
13831         }
13832     }
13833
13834   /* invert the horizontal alignment for RTL languages */
13835   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13836     x_align = 1.0 - x_align;
13837
13838   if (!x_fill)
13839     {
13840       allocation.x1 = x_offset
13841                     + ((available_width - child_width) * x_align);
13842       allocation.x2 = allocation.x1 + child_width;
13843     }
13844
13845   if (!y_fill)
13846     {
13847       allocation.y1 = y_offset
13848                     + ((available_height - child_height) * y_align);
13849       allocation.y2 = allocation.y1 + child_height;
13850     }
13851
13852 out:
13853   clutter_actor_box_clamp_to_pixel (&allocation);
13854   clutter_actor_allocate (self, &allocation, flags);
13855 }
13856
13857 /**
13858  * clutter_actor_grab_key_focus:
13859  * @self: a #ClutterActor
13860  *
13861  * Sets the key focus of the #ClutterStage including @self
13862  * to this #ClutterActor.
13863  *
13864  * Since: 1.0
13865  */
13866 void
13867 clutter_actor_grab_key_focus (ClutterActor *self)
13868 {
13869   ClutterActor *stage;
13870
13871   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13872
13873   stage = _clutter_actor_get_stage_internal (self);
13874   if (stage != NULL)
13875     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13876 }
13877
13878 /**
13879  * clutter_actor_get_pango_context:
13880  * @self: a #ClutterActor
13881  *
13882  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13883  * is already configured using the appropriate font map, resolution
13884  * and font options.
13885  *
13886  * Unlike clutter_actor_create_pango_context(), this context is owend
13887  * by the #ClutterActor and it will be updated each time the options
13888  * stored by the #ClutterBackend change.
13889  *
13890  * You can use the returned #PangoContext to create a #PangoLayout
13891  * and render text using cogl_pango_render_layout() to reuse the
13892  * glyphs cache also used by Clutter.
13893  *
13894  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13895  *   The returned #PangoContext is owned by the actor and should not be
13896  *   unreferenced by the application code
13897  *
13898  * Since: 1.0
13899  */
13900 PangoContext *
13901 clutter_actor_get_pango_context (ClutterActor *self)
13902 {
13903   ClutterActorPrivate *priv;
13904
13905   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13906
13907   priv = self->priv;
13908
13909   if (priv->pango_context != NULL)
13910     return priv->pango_context;
13911
13912   priv->pango_context = _clutter_context_get_pango_context ();
13913   g_object_ref (priv->pango_context);
13914
13915   return priv->pango_context;
13916 }
13917
13918 /**
13919  * clutter_actor_create_pango_context:
13920  * @self: a #ClutterActor
13921  *
13922  * Creates a #PangoContext for the given actor. The #PangoContext
13923  * is already configured using the appropriate font map, resolution
13924  * and font options.
13925  *
13926  * See also clutter_actor_get_pango_context().
13927  *
13928  * Return value: (transfer full): the newly created #PangoContext.
13929  *   Use g_object_unref() on the returned value to deallocate its
13930  *   resources
13931  *
13932  * Since: 1.0
13933  */
13934 PangoContext *
13935 clutter_actor_create_pango_context (ClutterActor *self)
13936 {
13937   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13938
13939   return _clutter_context_create_pango_context ();
13940 }
13941
13942 /**
13943  * clutter_actor_create_pango_layout:
13944  * @self: a #ClutterActor
13945  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13946  *
13947  * Creates a new #PangoLayout from the same #PangoContext used
13948  * by the #ClutterActor. The #PangoLayout is already configured
13949  * with the font map, resolution and font options, and the
13950  * given @text.
13951  *
13952  * If you want to keep around a #PangoLayout created by this
13953  * function you will have to connect to the #ClutterBackend::font-changed
13954  * and #ClutterBackend::resolution-changed signals, and call
13955  * pango_layout_context_changed() in response to them.
13956  *
13957  * Return value: (transfer full): the newly created #PangoLayout.
13958  *   Use g_object_unref() when done
13959  *
13960  * Since: 1.0
13961  */
13962 PangoLayout *
13963 clutter_actor_create_pango_layout (ClutterActor *self,
13964                                    const gchar  *text)
13965 {
13966   PangoContext *context;
13967   PangoLayout *layout;
13968
13969   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13970
13971   context = clutter_actor_get_pango_context (self);
13972   layout = pango_layout_new (context);
13973
13974   if (text)
13975     pango_layout_set_text (layout, text, -1);
13976
13977   return layout;
13978 }
13979
13980 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
13981  * ClutterOffscreenEffect.
13982  */
13983 void
13984 _clutter_actor_set_opacity_override (ClutterActor *self,
13985                                      gint          opacity)
13986 {
13987   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13988
13989   self->priv->opacity_override = opacity;
13990 }
13991
13992 gint
13993 _clutter_actor_get_opacity_override (ClutterActor *self)
13994 {
13995   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
13996
13997   return self->priv->opacity_override;
13998 }
13999
14000 /* Allows you to disable applying the actors model view transform during
14001  * a paint. Used by ClutterClone. */
14002 void
14003 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14004                                                 gboolean      enable)
14005 {
14006   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14007
14008   self->priv->enable_model_view_transform = enable;
14009 }
14010
14011 void
14012 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14013                                           gboolean      enable)
14014 {
14015   ClutterActorPrivate *priv;
14016
14017   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14018
14019   priv = self->priv;
14020
14021   priv->enable_paint_unmapped = enable;
14022
14023   if (priv->enable_paint_unmapped)
14024     {
14025       /* Make sure that the parents of the widget are realized first;
14026        * otherwise checks in clutter_actor_update_map_state() will
14027        * fail.
14028        */
14029       clutter_actor_realize (self);
14030
14031       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14032     }
14033   else
14034     {
14035       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14036     }
14037 }
14038
14039 static void
14040 clutter_anchor_coord_get_units (ClutterActor      *self,
14041                                 const AnchorCoord *coord,
14042                                 gfloat            *x,
14043                                 gfloat            *y,
14044                                 gfloat            *z)
14045 {
14046   if (coord->is_fractional)
14047     {
14048       gfloat actor_width, actor_height;
14049
14050       clutter_actor_get_size (self, &actor_width, &actor_height);
14051
14052       if (x)
14053         *x = actor_width * coord->v.fraction.x;
14054
14055       if (y)
14056         *y = actor_height * coord->v.fraction.y;
14057
14058       if (z)
14059         *z = 0;
14060     }
14061   else
14062     {
14063       if (x)
14064         *x = coord->v.units.x;
14065
14066       if (y)
14067         *y = coord->v.units.y;
14068
14069       if (z)
14070         *z = coord->v.units.z;
14071     }
14072 }
14073
14074 static void
14075 clutter_anchor_coord_set_units (AnchorCoord *coord,
14076                                 gfloat       x,
14077                                 gfloat       y,
14078                                 gfloat       z)
14079 {
14080   coord->is_fractional = FALSE;
14081   coord->v.units.x = x;
14082   coord->v.units.y = y;
14083   coord->v.units.z = z;
14084 }
14085
14086 static ClutterGravity
14087 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14088 {
14089   if (coord->is_fractional)
14090     {
14091       if (coord->v.fraction.x == 0.0)
14092         {
14093           if (coord->v.fraction.y == 0.0)
14094             return CLUTTER_GRAVITY_NORTH_WEST;
14095           else if (coord->v.fraction.y == 0.5)
14096             return CLUTTER_GRAVITY_WEST;
14097           else if (coord->v.fraction.y == 1.0)
14098             return CLUTTER_GRAVITY_SOUTH_WEST;
14099           else
14100             return CLUTTER_GRAVITY_NONE;
14101         }
14102       else if (coord->v.fraction.x == 0.5)
14103         {
14104           if (coord->v.fraction.y == 0.0)
14105             return CLUTTER_GRAVITY_NORTH;
14106           else if (coord->v.fraction.y == 0.5)
14107             return CLUTTER_GRAVITY_CENTER;
14108           else if (coord->v.fraction.y == 1.0)
14109             return CLUTTER_GRAVITY_SOUTH;
14110           else
14111             return CLUTTER_GRAVITY_NONE;
14112         }
14113       else if (coord->v.fraction.x == 1.0)
14114         {
14115           if (coord->v.fraction.y == 0.0)
14116             return CLUTTER_GRAVITY_NORTH_EAST;
14117           else if (coord->v.fraction.y == 0.5)
14118             return CLUTTER_GRAVITY_EAST;
14119           else if (coord->v.fraction.y == 1.0)
14120             return CLUTTER_GRAVITY_SOUTH_EAST;
14121           else
14122             return CLUTTER_GRAVITY_NONE;
14123         }
14124       else
14125         return CLUTTER_GRAVITY_NONE;
14126     }
14127   else
14128     return CLUTTER_GRAVITY_NONE;
14129 }
14130
14131 static void
14132 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14133                                   ClutterGravity  gravity)
14134 {
14135   switch (gravity)
14136     {
14137     case CLUTTER_GRAVITY_NORTH:
14138       coord->v.fraction.x = 0.5;
14139       coord->v.fraction.y = 0.0;
14140       break;
14141
14142     case CLUTTER_GRAVITY_NORTH_EAST:
14143       coord->v.fraction.x = 1.0;
14144       coord->v.fraction.y = 0.0;
14145       break;
14146
14147     case CLUTTER_GRAVITY_EAST:
14148       coord->v.fraction.x = 1.0;
14149       coord->v.fraction.y = 0.5;
14150       break;
14151
14152     case CLUTTER_GRAVITY_SOUTH_EAST:
14153       coord->v.fraction.x = 1.0;
14154       coord->v.fraction.y = 1.0;
14155       break;
14156
14157     case CLUTTER_GRAVITY_SOUTH:
14158       coord->v.fraction.x = 0.5;
14159       coord->v.fraction.y = 1.0;
14160       break;
14161
14162     case CLUTTER_GRAVITY_SOUTH_WEST:
14163       coord->v.fraction.x = 0.0;
14164       coord->v.fraction.y = 1.0;
14165       break;
14166
14167     case CLUTTER_GRAVITY_WEST:
14168       coord->v.fraction.x = 0.0;
14169       coord->v.fraction.y = 0.5;
14170       break;
14171
14172     case CLUTTER_GRAVITY_NORTH_WEST:
14173       coord->v.fraction.x = 0.0;
14174       coord->v.fraction.y = 0.0;
14175       break;
14176
14177     case CLUTTER_GRAVITY_CENTER:
14178       coord->v.fraction.x = 0.5;
14179       coord->v.fraction.y = 0.5;
14180       break;
14181
14182     default:
14183       coord->v.fraction.x = 0.0;
14184       coord->v.fraction.y = 0.0;
14185       break;
14186     }
14187
14188   coord->is_fractional = TRUE;
14189 }
14190
14191 static gboolean
14192 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14193 {
14194   if (coord->is_fractional)
14195     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14196   else
14197     return (coord->v.units.x == 0.0
14198             && coord->v.units.y == 0.0
14199             && coord->v.units.z == 0.0);
14200 }
14201
14202 /**
14203  * clutter_actor_get_flags:
14204  * @self: a #ClutterActor
14205  *
14206  * Retrieves the flags set on @self
14207  *
14208  * Return value: a bitwise or of #ClutterActorFlags or 0
14209  *
14210  * Since: 1.0
14211  */
14212 ClutterActorFlags
14213 clutter_actor_get_flags (ClutterActor *self)
14214 {
14215   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14216
14217   return self->flags;
14218 }
14219
14220 /**
14221  * clutter_actor_set_flags:
14222  * @self: a #ClutterActor
14223  * @flags: the flags to set
14224  *
14225  * Sets @flags on @self
14226  *
14227  * This function will emit notifications for the changed properties
14228  *
14229  * Since: 1.0
14230  */
14231 void
14232 clutter_actor_set_flags (ClutterActor      *self,
14233                          ClutterActorFlags  flags)
14234 {
14235   ClutterActorFlags old_flags;
14236   GObject *obj;
14237   gboolean was_reactive_set, reactive_set;
14238   gboolean was_realized_set, realized_set;
14239   gboolean was_mapped_set, mapped_set;
14240   gboolean was_visible_set, visible_set;
14241
14242   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14243
14244   if (self->flags == flags)
14245     return;
14246
14247   obj = G_OBJECT (self);
14248   g_object_ref (obj);
14249   g_object_freeze_notify (obj);
14250
14251   old_flags = self->flags;
14252
14253   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14254   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14255   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14256   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14257
14258   self->flags |= flags;
14259
14260   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14261   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14262   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14263   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14264
14265   if (reactive_set != was_reactive_set)
14266     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14267
14268   if (realized_set != was_realized_set)
14269     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14270
14271   if (mapped_set != was_mapped_set)
14272     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14273
14274   if (visible_set != was_visible_set)
14275     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14276
14277   g_object_thaw_notify (obj);
14278   g_object_unref (obj);
14279 }
14280
14281 /**
14282  * clutter_actor_unset_flags:
14283  * @self: a #ClutterActor
14284  * @flags: the flags to unset
14285  *
14286  * Unsets @flags on @self
14287  *
14288  * This function will emit notifications for the changed properties
14289  *
14290  * Since: 1.0
14291  */
14292 void
14293 clutter_actor_unset_flags (ClutterActor      *self,
14294                            ClutterActorFlags  flags)
14295 {
14296   ClutterActorFlags old_flags;
14297   GObject *obj;
14298   gboolean was_reactive_set, reactive_set;
14299   gboolean was_realized_set, realized_set;
14300   gboolean was_mapped_set, mapped_set;
14301   gboolean was_visible_set, visible_set;
14302
14303   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14304
14305   obj = G_OBJECT (self);
14306   g_object_freeze_notify (obj);
14307
14308   old_flags = self->flags;
14309
14310   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14311   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14312   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14313   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14314
14315   self->flags &= ~flags;
14316
14317   if (self->flags == old_flags)
14318     return;
14319
14320   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14321   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14322   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14323   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14324
14325   if (reactive_set != was_reactive_set)
14326     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14327
14328   if (realized_set != was_realized_set)
14329     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14330
14331   if (mapped_set != was_mapped_set)
14332     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14333
14334   if (visible_set != was_visible_set)
14335     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14336
14337   g_object_thaw_notify (obj);
14338 }
14339
14340 /**
14341  * clutter_actor_get_transformation_matrix:
14342  * @self: a #ClutterActor
14343  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14344  *
14345  * Retrieves the transformations applied to @self relative to its
14346  * parent.
14347  *
14348  * Since: 1.0
14349  */
14350 void
14351 clutter_actor_get_transformation_matrix (ClutterActor *self,
14352                                          CoglMatrix   *matrix)
14353 {
14354   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14355
14356   cogl_matrix_init_identity (matrix);
14357
14358   _clutter_actor_apply_modelview_transform (self, matrix);
14359 }
14360
14361 void
14362 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14363                                    gboolean      is_in_clone_paint)
14364 {
14365   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14366   self->priv->in_clone_paint = is_in_clone_paint;
14367 }
14368
14369 /**
14370  * clutter_actor_is_in_clone_paint:
14371  * @self: a #ClutterActor
14372  *
14373  * Checks whether @self is being currently painted by a #ClutterClone
14374  *
14375  * This function is useful only inside the ::paint virtual function
14376  * implementations or within handlers for the #ClutterActor::paint
14377  * signal
14378  *
14379  * This function should not be used by applications
14380  *
14381  * Return value: %TRUE if the #ClutterActor is currently being painted
14382  *   by a #ClutterClone, and %FALSE otherwise
14383  *
14384  * Since: 1.0
14385  */
14386 gboolean
14387 clutter_actor_is_in_clone_paint (ClutterActor *self)
14388 {
14389   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14390
14391   return self->priv->in_clone_paint;
14392 }
14393
14394 static gboolean
14395 set_direction_recursive (ClutterActor *actor,
14396                          gpointer      user_data)
14397 {
14398   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14399
14400   clutter_actor_set_text_direction (actor, text_dir);
14401
14402   return TRUE;
14403 }
14404
14405 /**
14406  * clutter_actor_set_text_direction:
14407  * @self: a #ClutterActor
14408  * @text_dir: the text direction for @self
14409  *
14410  * Sets the #ClutterTextDirection for an actor
14411  *
14412  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14413  *
14414  * If @self implements #ClutterContainer then this function will recurse
14415  * inside all the children of @self (including the internal ones).
14416  *
14417  * Composite actors not implementing #ClutterContainer, or actors requiring
14418  * special handling when the text direction changes, should connect to
14419  * the #GObject::notify signal for the #ClutterActor:text-direction property
14420  *
14421  * Since: 1.2
14422  */
14423 void
14424 clutter_actor_set_text_direction (ClutterActor         *self,
14425                                   ClutterTextDirection  text_dir)
14426 {
14427   ClutterActorPrivate *priv;
14428
14429   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14430   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14431
14432   priv = self->priv;
14433
14434   if (priv->text_direction != text_dir)
14435     {
14436       priv->text_direction = text_dir;
14437
14438       /* we need to emit the notify::text-direction first, so that
14439        * the sub-classes can catch that and do specific handling of
14440        * the text direction; see clutter_text_direction_changed_cb()
14441        * inside clutter-text.c
14442        */
14443       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14444
14445       _clutter_actor_foreach_child (self, set_direction_recursive,
14446                                     GINT_TO_POINTER (text_dir));
14447
14448       clutter_actor_queue_relayout (self);
14449     }
14450 }
14451
14452 void
14453 _clutter_actor_set_has_pointer (ClutterActor *self,
14454                                 gboolean      has_pointer)
14455 {
14456   ClutterActorPrivate *priv = self->priv;
14457
14458   if (priv->has_pointer != has_pointer)
14459     {
14460       priv->has_pointer = has_pointer;
14461
14462       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14463     }
14464 }
14465
14466 /**
14467  * clutter_actor_get_text_direction:
14468  * @self: a #ClutterActor
14469  *
14470  * Retrieves the value set using clutter_actor_set_text_direction()
14471  *
14472  * If no text direction has been previously set, the default text
14473  * direction, as returned by clutter_get_default_text_direction(), will
14474  * be returned instead
14475  *
14476  * Return value: the #ClutterTextDirection for the actor
14477  *
14478  * Since: 1.2
14479  */
14480 ClutterTextDirection
14481 clutter_actor_get_text_direction (ClutterActor *self)
14482 {
14483   ClutterActorPrivate *priv;
14484
14485   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14486                         CLUTTER_TEXT_DIRECTION_LTR);
14487
14488   priv = self->priv;
14489
14490   /* if no direction has been set yet use the default */
14491   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14492     priv->text_direction = clutter_get_default_text_direction ();
14493
14494   return priv->text_direction;
14495 }
14496
14497 /**
14498  * clutter_actor_push_internal:
14499  * @self: a #ClutterActor
14500  *
14501  * Should be used by actors implementing the #ClutterContainer and with
14502  * internal children added through clutter_actor_set_parent(), for instance:
14503  *
14504  * |[
14505  *   static void
14506  *   my_actor_init (MyActor *self)
14507  *   {
14508  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14509  *
14510  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14511  *
14512  *     /&ast; calling clutter_actor_set_parent() now will result in
14513  *      &ast; the internal flag being set on a child of MyActor
14514  *      &ast;/
14515  *
14516  *     /&ast; internal child - a background texture &ast;/
14517  *     self->priv->background_tex = clutter_texture_new ();
14518  *     clutter_actor_set_parent (self->priv->background_tex,
14519  *                               CLUTTER_ACTOR (self));
14520  *
14521  *     /&ast; internal child - a label &ast;/
14522  *     self->priv->label = clutter_text_new ();
14523  *     clutter_actor_set_parent (self->priv->label,
14524  *                               CLUTTER_ACTOR (self));
14525  *
14526  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14527  *
14528  *     /&ast; calling clutter_actor_set_parent() now will not result in
14529  *      &ast; the internal flag being set on a child of MyActor
14530  *      &ast;/
14531  *   }
14532  * ]|
14533  *
14534  * This function will be used by Clutter to toggle an "internal child"
14535  * flag whenever clutter_actor_set_parent() is called; internal children
14536  * are handled differently by Clutter, specifically when destroying their
14537  * parent.
14538  *
14539  * Call clutter_actor_pop_internal() when you finished adding internal
14540  * children.
14541  *
14542  * Nested calls to clutter_actor_push_internal() are allowed, but each
14543  * one must by followed by a clutter_actor_pop_internal() call.
14544  *
14545  * Since: 1.2
14546  *
14547  * Deprecated: 1.10: All children of an actor are accessible through
14548  *   the #ClutterActor API, and #ClutterActor implements the
14549  *   #ClutterContainer interface, so this function is only useful
14550  *   for legacy containers overriding the default implementation.
14551  */
14552 void
14553 clutter_actor_push_internal (ClutterActor *self)
14554 {
14555   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14556
14557   self->priv->internal_child += 1;
14558 }
14559
14560 /**
14561  * clutter_actor_pop_internal:
14562  * @self: a #ClutterActor
14563  *
14564  * Disables the effects of clutter_actor_push_internal().
14565  *
14566  * Since: 1.2
14567  *
14568  * Deprecated: 1.10: All children of an actor are accessible through
14569  *   the #ClutterActor API. This function is only useful for legacy
14570  *   containers overriding the default implementation of the
14571  *   #ClutterContainer interface.
14572  */
14573 void
14574 clutter_actor_pop_internal (ClutterActor *self)
14575 {
14576   ClutterActorPrivate *priv;
14577
14578   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14579
14580   priv = self->priv;
14581
14582   if (priv->internal_child == 0)
14583     {
14584       g_warning ("Mismatched %s: you need to call "
14585                  "clutter_actor_push_composite() at least once before "
14586                  "calling this function", G_STRFUNC);
14587       return;
14588     }
14589
14590   priv->internal_child -= 1;
14591 }
14592
14593 /**
14594  * clutter_actor_has_pointer:
14595  * @self: a #ClutterActor
14596  *
14597  * Checks whether an actor contains the pointer of a
14598  * #ClutterInputDevice
14599  *
14600  * Return value: %TRUE if the actor contains the pointer, and
14601  *   %FALSE otherwise
14602  *
14603  * Since: 1.2
14604  */
14605 gboolean
14606 clutter_actor_has_pointer (ClutterActor *self)
14607 {
14608   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14609
14610   return self->priv->has_pointer;
14611 }
14612
14613 /* XXX: This is a workaround for not being able to break the ABI of
14614  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14615  * clutter_actor_queue_clipped_redraw() for details.
14616  */
14617 ClutterPaintVolume *
14618 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14619 {
14620   return g_object_get_data (G_OBJECT (self),
14621                             "-clutter-actor-queue-redraw-clip");
14622 }
14623
14624 void
14625 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14626                                       ClutterPaintVolume *clip)
14627 {
14628   g_object_set_data (G_OBJECT (self),
14629                      "-clutter-actor-queue-redraw-clip",
14630                      clip);
14631 }
14632
14633 /**
14634  * clutter_actor_has_allocation:
14635  * @self: a #ClutterActor
14636  *
14637  * Checks if the actor has an up-to-date allocation assigned to
14638  * it. This means that the actor should have an allocation: it's
14639  * visible and has a parent. It also means that there is no
14640  * outstanding relayout request in progress for the actor or its
14641  * children (There might be other outstanding layout requests in
14642  * progress that will cause the actor to get a new allocation
14643  * when the stage is laid out, however).
14644  *
14645  * If this function returns %FALSE, then the actor will normally
14646  * be allocated before it is next drawn on the screen.
14647  *
14648  * Return value: %TRUE if the actor has an up-to-date allocation
14649  *
14650  * Since: 1.4
14651  */
14652 gboolean
14653 clutter_actor_has_allocation (ClutterActor *self)
14654 {
14655   ClutterActorPrivate *priv;
14656
14657   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14658
14659   priv = self->priv;
14660
14661   return priv->parent != NULL &&
14662          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14663          !priv->needs_allocation;
14664 }
14665
14666 /**
14667  * clutter_actor_add_action:
14668  * @self: a #ClutterActor
14669  * @action: a #ClutterAction
14670  *
14671  * Adds @action to the list of actions applied to @self
14672  *
14673  * A #ClutterAction can only belong to one actor at a time
14674  *
14675  * The #ClutterActor will hold a reference on @action until either
14676  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14677  * is called
14678  *
14679  * Since: 1.4
14680  */
14681 void
14682 clutter_actor_add_action (ClutterActor  *self,
14683                           ClutterAction *action)
14684 {
14685   ClutterActorPrivate *priv;
14686
14687   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14688   g_return_if_fail (CLUTTER_IS_ACTION (action));
14689
14690   priv = self->priv;
14691
14692   if (priv->actions == NULL)
14693     {
14694       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14695       priv->actions->actor = self;
14696     }
14697
14698   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14699
14700   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14701 }
14702
14703 /**
14704  * clutter_actor_add_action_with_name:
14705  * @self: a #ClutterActor
14706  * @name: the name to set on the action
14707  * @action: a #ClutterAction
14708  *
14709  * A convenience function for setting the name of a #ClutterAction
14710  * while adding it to the list of actions applied to @self
14711  *
14712  * This function is the logical equivalent of:
14713  *
14714  * |[
14715  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14716  *   clutter_actor_add_action (self, action);
14717  * ]|
14718  *
14719  * Since: 1.4
14720  */
14721 void
14722 clutter_actor_add_action_with_name (ClutterActor  *self,
14723                                     const gchar   *name,
14724                                     ClutterAction *action)
14725 {
14726   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14727   g_return_if_fail (name != NULL);
14728   g_return_if_fail (CLUTTER_IS_ACTION (action));
14729
14730   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14731   clutter_actor_add_action (self, action);
14732 }
14733
14734 /**
14735  * clutter_actor_remove_action:
14736  * @self: a #ClutterActor
14737  * @action: a #ClutterAction
14738  *
14739  * Removes @action from the list of actions applied to @self
14740  *
14741  * The reference held by @self on the #ClutterAction will be released
14742  *
14743  * Since: 1.4
14744  */
14745 void
14746 clutter_actor_remove_action (ClutterActor  *self,
14747                              ClutterAction *action)
14748 {
14749   ClutterActorPrivate *priv;
14750
14751   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14752   g_return_if_fail (CLUTTER_IS_ACTION (action));
14753
14754   priv = self->priv;
14755
14756   if (priv->actions == NULL)
14757     return;
14758
14759   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14760
14761   if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
14762     g_clear_object (&priv->actions);
14763
14764   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14765 }
14766
14767 /**
14768  * clutter_actor_remove_action_by_name:
14769  * @self: a #ClutterActor
14770  * @name: the name of the action to remove
14771  *
14772  * Removes the #ClutterAction with the given name from the list
14773  * of actions applied to @self
14774  *
14775  * Since: 1.4
14776  */
14777 void
14778 clutter_actor_remove_action_by_name (ClutterActor *self,
14779                                      const gchar  *name)
14780 {
14781   ClutterActorPrivate *priv;
14782   ClutterActorMeta *meta;
14783
14784   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14785   g_return_if_fail (name != NULL);
14786
14787   priv = self->priv;
14788
14789   if (priv->actions == NULL)
14790     return;
14791
14792   meta = _clutter_meta_group_get_meta (priv->actions, name);
14793   if (meta == NULL)
14794     return;
14795
14796   _clutter_meta_group_remove_meta (priv->actions, meta);
14797
14798   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14799 }
14800
14801 /**
14802  * clutter_actor_get_actions:
14803  * @self: a #ClutterActor
14804  *
14805  * Retrieves the list of actions applied to @self
14806  *
14807  * Return value: (transfer container) (element-type Clutter.Action): a copy
14808  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14809  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14810  *   allocated by the returned #GList
14811  *
14812  * Since: 1.4
14813  */
14814 GList *
14815 clutter_actor_get_actions (ClutterActor *self)
14816 {
14817   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14818
14819   if (self->priv->actions == NULL)
14820     return NULL;
14821
14822   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14823 }
14824
14825 /**
14826  * clutter_actor_get_action:
14827  * @self: a #ClutterActor
14828  * @name: the name of the action to retrieve
14829  *
14830  * Retrieves the #ClutterAction with the given name in the list
14831  * of actions applied to @self
14832  *
14833  * Return value: (transfer none): a #ClutterAction for the given
14834  *   name, or %NULL. The returned #ClutterAction is owned by the
14835  *   actor and it should not be unreferenced directly
14836  *
14837  * Since: 1.4
14838  */
14839 ClutterAction *
14840 clutter_actor_get_action (ClutterActor *self,
14841                           const gchar  *name)
14842 {
14843   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14844   g_return_val_if_fail (name != NULL, NULL);
14845
14846   if (self->priv->actions == NULL)
14847     return NULL;
14848
14849   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14850 }
14851
14852 /**
14853  * clutter_actor_clear_actions:
14854  * @self: a #ClutterActor
14855  *
14856  * Clears the list of actions applied to @self
14857  *
14858  * Since: 1.4
14859  */
14860 void
14861 clutter_actor_clear_actions (ClutterActor *self)
14862 {
14863   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14864
14865   if (self->priv->actions == NULL)
14866     return;
14867
14868   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14869 }
14870
14871 /**
14872  * clutter_actor_add_constraint:
14873  * @self: a #ClutterActor
14874  * @constraint: a #ClutterConstraint
14875  *
14876  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14877  * to @self
14878  *
14879  * The #ClutterActor will hold a reference on the @constraint until
14880  * either clutter_actor_remove_constraint() or
14881  * clutter_actor_clear_constraints() is called.
14882  *
14883  * Since: 1.4
14884  */
14885 void
14886 clutter_actor_add_constraint (ClutterActor      *self,
14887                               ClutterConstraint *constraint)
14888 {
14889   ClutterActorPrivate *priv;
14890
14891   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14892   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14893
14894   priv = self->priv;
14895
14896   if (priv->constraints == NULL)
14897     {
14898       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14899       priv->constraints->actor = self;
14900     }
14901
14902   _clutter_meta_group_add_meta (priv->constraints,
14903                                 CLUTTER_ACTOR_META (constraint));
14904   clutter_actor_queue_relayout (self);
14905
14906   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14907 }
14908
14909 /**
14910  * clutter_actor_add_constraint_with_name:
14911  * @self: a #ClutterActor
14912  * @name: the name to set on the constraint
14913  * @constraint: a #ClutterConstraint
14914  *
14915  * A convenience function for setting the name of a #ClutterConstraint
14916  * while adding it to the list of constraints applied to @self
14917  *
14918  * This function is the logical equivalent of:
14919  *
14920  * |[
14921  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14922  *   clutter_actor_add_constraint (self, constraint);
14923  * ]|
14924  *
14925  * Since: 1.4
14926  */
14927 void
14928 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14929                                         const gchar       *name,
14930                                         ClutterConstraint *constraint)
14931 {
14932   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14933   g_return_if_fail (name != NULL);
14934   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14935
14936   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14937   clutter_actor_add_constraint (self, constraint);
14938 }
14939
14940 /**
14941  * clutter_actor_remove_constraint:
14942  * @self: a #ClutterActor
14943  * @constraint: a #ClutterConstraint
14944  *
14945  * Removes @constraint from the list of constraints applied to @self
14946  *
14947  * The reference held by @self on the #ClutterConstraint will be released
14948  *
14949  * Since: 1.4
14950  */
14951 void
14952 clutter_actor_remove_constraint (ClutterActor      *self,
14953                                  ClutterConstraint *constraint)
14954 {
14955   ClutterActorPrivate *priv;
14956
14957   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14958   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14959
14960   priv = self->priv;
14961
14962   if (priv->constraints == NULL)
14963     return;
14964
14965   _clutter_meta_group_remove_meta (priv->constraints,
14966                                    CLUTTER_ACTOR_META (constraint));
14967
14968   if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
14969     g_clear_object (&priv->constraints);
14970
14971   clutter_actor_queue_relayout (self);
14972
14973   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14974 }
14975
14976 /**
14977  * clutter_actor_remove_constraint_by_name:
14978  * @self: a #ClutterActor
14979  * @name: the name of the constraint to remove
14980  *
14981  * Removes the #ClutterConstraint with the given name from the list
14982  * of constraints applied to @self
14983  *
14984  * Since: 1.4
14985  */
14986 void
14987 clutter_actor_remove_constraint_by_name (ClutterActor *self,
14988                                          const gchar  *name)
14989 {
14990   ClutterActorPrivate *priv;
14991   ClutterActorMeta *meta;
14992
14993   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14994   g_return_if_fail (name != NULL);
14995
14996   priv = self->priv;
14997
14998   if (priv->constraints == NULL)
14999     return;
15000
15001   meta = _clutter_meta_group_get_meta (priv->constraints, name);
15002   if (meta == NULL)
15003     return;
15004
15005   _clutter_meta_group_remove_meta (priv->constraints, meta);
15006   clutter_actor_queue_relayout (self);
15007 }
15008
15009 /**
15010  * clutter_actor_get_constraints:
15011  * @self: a #ClutterActor
15012  *
15013  * Retrieves the list of constraints applied to @self
15014  *
15015  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15016  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15017  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15018  *   allocated by the returned #GList
15019  *
15020  * Since: 1.4
15021  */
15022 GList *
15023 clutter_actor_get_constraints (ClutterActor *self)
15024 {
15025   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15026
15027   if (self->priv->constraints == NULL)
15028     return NULL;
15029
15030   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15031 }
15032
15033 /**
15034  * clutter_actor_get_constraint:
15035  * @self: a #ClutterActor
15036  * @name: the name of the constraint to retrieve
15037  *
15038  * Retrieves the #ClutterConstraint with the given name in the list
15039  * of constraints applied to @self
15040  *
15041  * Return value: (transfer none): a #ClutterConstraint for the given
15042  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15043  *   actor and it should not be unreferenced directly
15044  *
15045  * Since: 1.4
15046  */
15047 ClutterConstraint *
15048 clutter_actor_get_constraint (ClutterActor *self,
15049                               const gchar  *name)
15050 {
15051   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15052   g_return_val_if_fail (name != NULL, NULL);
15053
15054   if (self->priv->constraints == NULL)
15055     return NULL;
15056
15057   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15058 }
15059
15060 /**
15061  * clutter_actor_clear_constraints:
15062  * @self: a #ClutterActor
15063  *
15064  * Clears the list of constraints applied to @self
15065  *
15066  * Since: 1.4
15067  */
15068 void
15069 clutter_actor_clear_constraints (ClutterActor *self)
15070 {
15071   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15072
15073   if (self->priv->constraints == NULL)
15074     return;
15075
15076   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15077
15078   clutter_actor_queue_relayout (self);
15079 }
15080
15081 /**
15082  * clutter_actor_set_clip_to_allocation:
15083  * @self: a #ClutterActor
15084  * @clip_set: %TRUE to apply a clip tracking the allocation
15085  *
15086  * Sets whether @self should be clipped to the same size as its
15087  * allocation
15088  *
15089  * Since: 1.4
15090  */
15091 void
15092 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15093                                       gboolean      clip_set)
15094 {
15095   ClutterActorPrivate *priv;
15096
15097   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15098
15099   clip_set = !!clip_set;
15100
15101   priv = self->priv;
15102
15103   if (priv->clip_to_allocation != clip_set)
15104     {
15105       priv->clip_to_allocation = clip_set;
15106
15107       clutter_actor_queue_redraw (self);
15108
15109       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15110     }
15111 }
15112
15113 /**
15114  * clutter_actor_get_clip_to_allocation:
15115  * @self: a #ClutterActor
15116  *
15117  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15118  *
15119  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15120  *
15121  * Since: 1.4
15122  */
15123 gboolean
15124 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15125 {
15126   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15127
15128   return self->priv->clip_to_allocation;
15129 }
15130
15131 /**
15132  * clutter_actor_add_effect:
15133  * @self: a #ClutterActor
15134  * @effect: a #ClutterEffect
15135  *
15136  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15137  *
15138  * The #ClutterActor will hold a reference on the @effect until either
15139  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15140  * called.
15141  *
15142  * Since: 1.4
15143  */
15144 void
15145 clutter_actor_add_effect (ClutterActor  *self,
15146                           ClutterEffect *effect)
15147 {
15148   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15149   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15150
15151   _clutter_actor_add_effect_internal (self, effect);
15152
15153   clutter_actor_queue_redraw (self);
15154
15155   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15156 }
15157
15158 /**
15159  * clutter_actor_add_effect_with_name:
15160  * @self: a #ClutterActor
15161  * @name: the name to set on the effect
15162  * @effect: a #ClutterEffect
15163  *
15164  * A convenience function for setting the name of a #ClutterEffect
15165  * while adding it to the list of effectss applied to @self
15166  *
15167  * This function is the logical equivalent of:
15168  *
15169  * |[
15170  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15171  *   clutter_actor_add_effect (self, effect);
15172  * ]|
15173  *
15174  * Since: 1.4
15175  */
15176 void
15177 clutter_actor_add_effect_with_name (ClutterActor  *self,
15178                                     const gchar   *name,
15179                                     ClutterEffect *effect)
15180 {
15181   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15182   g_return_if_fail (name != NULL);
15183   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15184
15185   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15186   clutter_actor_add_effect (self, effect);
15187 }
15188
15189 /**
15190  * clutter_actor_remove_effect:
15191  * @self: a #ClutterActor
15192  * @effect: a #ClutterEffect
15193  *
15194  * Removes @effect from the list of effects applied to @self
15195  *
15196  * The reference held by @self on the #ClutterEffect will be released
15197  *
15198  * Since: 1.4
15199  */
15200 void
15201 clutter_actor_remove_effect (ClutterActor  *self,
15202                              ClutterEffect *effect)
15203 {
15204   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15205   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15206
15207   _clutter_actor_remove_effect_internal (self, effect);
15208
15209   clutter_actor_queue_redraw (self);
15210
15211   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15212 }
15213
15214 /**
15215  * clutter_actor_remove_effect_by_name:
15216  * @self: a #ClutterActor
15217  * @name: the name of the effect to remove
15218  *
15219  * Removes the #ClutterEffect with the given name from the list
15220  * of effects applied to @self
15221  *
15222  * Since: 1.4
15223  */
15224 void
15225 clutter_actor_remove_effect_by_name (ClutterActor *self,
15226                                      const gchar  *name)
15227 {
15228   ClutterActorPrivate *priv;
15229   ClutterActorMeta *meta;
15230
15231   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15232   g_return_if_fail (name != NULL);
15233
15234   priv = self->priv;
15235
15236   if (priv->effects == NULL)
15237     return;
15238
15239   meta = _clutter_meta_group_get_meta (priv->effects, name);
15240   if (meta == NULL)
15241     return;
15242
15243   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15244 }
15245
15246 /**
15247  * clutter_actor_get_effects:
15248  * @self: a #ClutterActor
15249  *
15250  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15251  *
15252  * Return value: (transfer container) (element-type Clutter.Effect): a list
15253  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15254  *   list are owned by Clutter and they should not be freed. You should
15255  *   free the returned list using g_list_free() when done
15256  *
15257  * Since: 1.4
15258  */
15259 GList *
15260 clutter_actor_get_effects (ClutterActor *self)
15261 {
15262   ClutterActorPrivate *priv;
15263
15264   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15265
15266   priv = self->priv;
15267
15268   if (priv->effects == NULL)
15269     return NULL;
15270
15271   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15272 }
15273
15274 /**
15275  * clutter_actor_get_effect:
15276  * @self: a #ClutterActor
15277  * @name: the name of the effect to retrieve
15278  *
15279  * Retrieves the #ClutterEffect with the given name in the list
15280  * of effects applied to @self
15281  *
15282  * Return value: (transfer none): a #ClutterEffect for the given
15283  *   name, or %NULL. The returned #ClutterEffect is owned by the
15284  *   actor and it should not be unreferenced directly
15285  *
15286  * Since: 1.4
15287  */
15288 ClutterEffect *
15289 clutter_actor_get_effect (ClutterActor *self,
15290                           const gchar  *name)
15291 {
15292   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15293   g_return_val_if_fail (name != NULL, NULL);
15294
15295   if (self->priv->effects == NULL)
15296     return NULL;
15297
15298   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15299 }
15300
15301 /**
15302  * clutter_actor_clear_effects:
15303  * @self: a #ClutterActor
15304  *
15305  * Clears the list of effects applied to @self
15306  *
15307  * Since: 1.4
15308  */
15309 void
15310 clutter_actor_clear_effects (ClutterActor *self)
15311 {
15312   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15313
15314   if (self->priv->effects == NULL)
15315     return;
15316
15317   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15318
15319   clutter_actor_queue_redraw (self);
15320 }
15321
15322 /**
15323  * clutter_actor_has_key_focus:
15324  * @self: a #ClutterActor
15325  *
15326  * Checks whether @self is the #ClutterActor that has key focus
15327  *
15328  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15329  *
15330  * Since: 1.4
15331  */
15332 gboolean
15333 clutter_actor_has_key_focus (ClutterActor *self)
15334 {
15335   ClutterActor *stage;
15336
15337   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15338
15339   stage = _clutter_actor_get_stage_internal (self);
15340   if (stage == NULL)
15341     return FALSE;
15342
15343   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15344 }
15345
15346 static gboolean
15347 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15348                                       ClutterPaintVolume *pv)
15349 {
15350   ClutterActorPrivate *priv = self->priv;
15351
15352   /* Actors are only expected to report a valid paint volume
15353    * while they have a valid allocation. */
15354   if (G_UNLIKELY (priv->needs_allocation))
15355     {
15356       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15357                     "Actor needs allocation",
15358                     _clutter_actor_get_debug_name (self));
15359       return FALSE;
15360     }
15361
15362   /* Check if there are any handlers connected to the paint
15363    * signal. If there are then all bets are off for what the paint
15364    * volume for this actor might possibly be!
15365    *
15366    * XXX: It's expected that this is going to end up being quite a
15367    * costly check to have to do here, but we haven't come up with
15368    * another solution that can reliably catch paint signal handlers at
15369    * the right time to either avoid artefacts due to invalid stage
15370    * clipping or due to incorrect culling.
15371    *
15372    * Previously we checked in clutter_actor_paint(), but at that time
15373    * we may already be using a stage clip that could be derived from
15374    * an invalid paint-volume. We used to try and handle that by
15375    * queuing a follow up, unclipped, redraw but still the previous
15376    * checking wasn't enough to catch invalid volumes involved in
15377    * culling (considering that containers may derive their volume from
15378    * children that haven't yet been painted)
15379    *
15380    * Longer term, improved solutions could be:
15381    * - Disallow painting in the paint signal, only allow using it
15382    *   for tracking when paints happen. We can add another API that
15383    *   allows monkey patching the paint of arbitrary actors but in a
15384    *   more controlled way and that also supports modifying the
15385    *   paint-volume.
15386    * - If we could be notified somehow when signal handlers are
15387    *   connected we wouldn't have to poll for handlers like this.
15388    */
15389   if (g_signal_has_handler_pending (self,
15390                                     actor_signals[PAINT],
15391                                     0,
15392                                     TRUE))
15393     {
15394       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15395                     "Actor has \"paint\" signal handlers",
15396                     _clutter_actor_get_debug_name (self));
15397       return FALSE;
15398     }
15399
15400   _clutter_paint_volume_init_static (pv, self);
15401
15402   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15403     {
15404       clutter_paint_volume_free (pv);
15405       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15406                     "Actor failed to report a volume",
15407                     _clutter_actor_get_debug_name (self));
15408       return FALSE;
15409     }
15410
15411   /* since effects can modify the paint volume, we allow them to actually
15412    * do this by making get_paint_volume() "context sensitive"
15413    */
15414   if (priv->effects != NULL)
15415     {
15416       if (priv->current_effect != NULL)
15417         {
15418           const GList *effects, *l;
15419
15420           /* if we are being called from within the paint sequence of
15421            * an actor, get the paint volume up to the current effect
15422            */
15423           effects = _clutter_meta_group_peek_metas (priv->effects);
15424           for (l = effects;
15425                l != NULL || (l != NULL && l->data != priv->current_effect);
15426                l = l->next)
15427             {
15428               if (!_clutter_effect_get_paint_volume (l->data, pv))
15429                 {
15430                   clutter_paint_volume_free (pv);
15431                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15432                                 "Effect (%s) failed to report a volume",
15433                                 _clutter_actor_get_debug_name (self),
15434                                 _clutter_actor_meta_get_debug_name (l->data));
15435                   return FALSE;
15436                 }
15437             }
15438         }
15439       else
15440         {
15441           const GList *effects, *l;
15442
15443           /* otherwise, get the cumulative volume */
15444           effects = _clutter_meta_group_peek_metas (priv->effects);
15445           for (l = effects; l != NULL; l = l->next)
15446             if (!_clutter_effect_get_paint_volume (l->data, pv))
15447               {
15448                 clutter_paint_volume_free (pv);
15449                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15450                               "Effect (%s) failed to report a volume",
15451                               _clutter_actor_get_debug_name (self),
15452                               _clutter_actor_meta_get_debug_name (l->data));
15453                 return FALSE;
15454               }
15455         }
15456     }
15457
15458   return TRUE;
15459 }
15460
15461 /* The public clutter_actor_get_paint_volume API returns a const
15462  * pointer since we return a pointer directly to the cached
15463  * PaintVolume associated with the actor and don't want the user to
15464  * inadvertently modify it, but for internal uses we sometimes need
15465  * access to the same PaintVolume but need to apply some book-keeping
15466  * modifications to it so we don't want a const pointer.
15467  */
15468 static ClutterPaintVolume *
15469 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15470 {
15471   ClutterActorPrivate *priv;
15472
15473   priv = self->priv;
15474
15475   if (priv->paint_volume_valid)
15476     clutter_paint_volume_free (&priv->paint_volume);
15477
15478   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15479     {
15480       priv->paint_volume_valid = TRUE;
15481       return &priv->paint_volume;
15482     }
15483   else
15484     {
15485       priv->paint_volume_valid = FALSE;
15486       return NULL;
15487     }
15488 }
15489
15490 /**
15491  * clutter_actor_get_paint_volume:
15492  * @self: a #ClutterActor
15493  *
15494  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15495  * when a paint volume can't be determined.
15496  *
15497  * The paint volume is defined as the 3D space occupied by an actor
15498  * when being painted.
15499  *
15500  * This function will call the <function>get_paint_volume()</function>
15501  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15502  * should not usually care about overriding the default implementation,
15503  * unless they are, for instance: painting outside their allocation, or
15504  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15505  * 3D depth).
15506  *
15507  * <note>2D actors overriding <function>get_paint_volume()</function>
15508  * ensure their volume has a depth of 0. (This will be true so long as
15509  * you don't call clutter_paint_volume_set_depth().)</note>
15510  *
15511  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15512  *   or %NULL if no volume could be determined. The returned pointer
15513  *   is not guaranteed to be valid across multiple frames; if you want
15514  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15515  *
15516  * Since: 1.6
15517  */
15518 const ClutterPaintVolume *
15519 clutter_actor_get_paint_volume (ClutterActor *self)
15520 {
15521   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15522
15523   return _clutter_actor_get_paint_volume_mutable (self);
15524 }
15525
15526 /**
15527  * clutter_actor_get_transformed_paint_volume:
15528  * @self: a #ClutterActor
15529  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15530  *    (or %NULL for the stage)
15531  *
15532  * Retrieves the 3D paint volume of an actor like
15533  * clutter_actor_get_paint_volume() does (Please refer to the
15534  * documentation of clutter_actor_get_paint_volume() for more
15535  * details.) and it additionally transforms the paint volume into the
15536  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15537  * is passed for @relative_to_ancestor)
15538  *
15539  * This can be used by containers that base their paint volume on
15540  * the volume of their children. Such containers can query the
15541  * transformed paint volume of all of its children and union them
15542  * together using clutter_paint_volume_union().
15543  *
15544  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15545  *   or %NULL if no volume could be determined. The returned pointer is
15546  *   not guaranteed to be valid across multiple frames; if you wish to
15547  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15548  *
15549  * Since: 1.6
15550  */
15551 const ClutterPaintVolume *
15552 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15553                                             ClutterActor *relative_to_ancestor)
15554 {
15555   const ClutterPaintVolume *volume;
15556   ClutterActor *stage;
15557   ClutterPaintVolume *transformed_volume;
15558
15559   stage = _clutter_actor_get_stage_internal (self);
15560   if (G_UNLIKELY (stage == NULL))
15561     return NULL;
15562
15563   if (relative_to_ancestor == NULL)
15564     relative_to_ancestor = stage;
15565
15566   volume = clutter_actor_get_paint_volume (self);
15567   if (volume == NULL)
15568     return NULL;
15569
15570   transformed_volume =
15571     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15572
15573   _clutter_paint_volume_copy_static (volume, transformed_volume);
15574
15575   _clutter_paint_volume_transform_relative (transformed_volume,
15576                                             relative_to_ancestor);
15577
15578   return transformed_volume;
15579 }
15580
15581 /**
15582  * clutter_actor_get_paint_box:
15583  * @self: a #ClutterActor
15584  * @box: (out): return location for a #ClutterActorBox
15585  *
15586  * Retrieves the paint volume of the passed #ClutterActor, and
15587  * transforms it into a 2D bounding box in stage coordinates.
15588  *
15589  * This function is useful to determine the on screen area occupied by
15590  * the actor. The box is only an approximation and may often be
15591  * considerably larger due to the optimizations used to calculate the
15592  * box. The box is never smaller though, so it can reliably be used
15593  * for culling.
15594  *
15595  * There are times when a 2D paint box can't be determined, e.g.
15596  * because the actor isn't yet parented under a stage or because
15597  * the actor is unable to determine a paint volume.
15598  *
15599  * Return value: %TRUE if a 2D paint box could be determined, else
15600  * %FALSE.
15601  *
15602  * Since: 1.6
15603  */
15604 gboolean
15605 clutter_actor_get_paint_box (ClutterActor    *self,
15606                              ClutterActorBox *box)
15607 {
15608   ClutterActor *stage;
15609   ClutterPaintVolume *pv;
15610
15611   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15612   g_return_val_if_fail (box != NULL, FALSE);
15613
15614   stage = _clutter_actor_get_stage_internal (self);
15615   if (G_UNLIKELY (!stage))
15616     return FALSE;
15617
15618   pv = _clutter_actor_get_paint_volume_mutable (self);
15619   if (G_UNLIKELY (!pv))
15620     return FALSE;
15621
15622   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15623
15624   return TRUE;
15625 }
15626
15627 /**
15628  * clutter_actor_has_overlaps:
15629  * @self: A #ClutterActor
15630  *
15631  * Asks the actor's implementation whether it may contain overlapping
15632  * primitives.
15633  *
15634  * For example; Clutter may use this to determine whether the painting
15635  * should be redirected to an offscreen buffer to correctly implement
15636  * the opacity property.
15637  *
15638  * Custom actors can override the default response by implementing the
15639  * #ClutterActor <function>has_overlaps</function> virtual function. See
15640  * clutter_actor_set_offscreen_redirect() for more information.
15641  *
15642  * Return value: %TRUE if the actor may have overlapping primitives, and
15643  *   %FALSE otherwise
15644  *
15645  * Since: 1.8
15646  */
15647 gboolean
15648 clutter_actor_has_overlaps (ClutterActor *self)
15649 {
15650   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15651
15652   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15653 }
15654
15655 /**
15656  * clutter_actor_has_effects:
15657  * @self: A #ClutterActor
15658  *
15659  * Returns whether the actor has any effects applied.
15660  *
15661  * Return value: %TRUE if the actor has any effects,
15662  *   %FALSE otherwise
15663  *
15664  * Since: 1.10
15665  */
15666 gboolean
15667 clutter_actor_has_effects (ClutterActor *self)
15668 {
15669   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15670
15671   if (self->priv->effects == NULL)
15672     return FALSE;
15673
15674   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15675 }
15676
15677 /**
15678  * clutter_actor_has_constraints:
15679  * @self: A #ClutterActor
15680  *
15681  * Returns whether the actor has any constraints applied.
15682  *
15683  * Return value: %TRUE if the actor has any constraints,
15684  *   %FALSE otherwise
15685  *
15686  * Since: 1.10
15687  */
15688 gboolean
15689 clutter_actor_has_constraints (ClutterActor *self)
15690 {
15691   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15692
15693   return self->priv->constraints != NULL;
15694 }
15695
15696 /**
15697  * clutter_actor_has_actions:
15698  * @self: A #ClutterActor
15699  *
15700  * Returns whether the actor has any actions applied.
15701  *
15702  * Return value: %TRUE if the actor has any actions,
15703  *   %FALSE otherwise
15704  *
15705  * Since: 1.10
15706  */
15707 gboolean
15708 clutter_actor_has_actions (ClutterActor *self)
15709 {
15710   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15711
15712   return self->priv->actions != NULL;
15713 }
15714
15715 /**
15716  * clutter_actor_get_n_children:
15717  * @self: a #ClutterActor
15718  *
15719  * Retrieves the number of children of @self.
15720  *
15721  * Return value: the number of children of an actor
15722  *
15723  * Since: 1.10
15724  */
15725 gint
15726 clutter_actor_get_n_children (ClutterActor *self)
15727 {
15728   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15729
15730   return self->priv->n_children;
15731 }
15732
15733 /**
15734  * clutter_actor_get_child_at_index:
15735  * @self: a #ClutterActor
15736  * @index_: the position in the list of children
15737  *
15738  * Retrieves the actor at the given @index_ inside the list of
15739  * children of @self.
15740  *
15741  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15742  *
15743  * Since: 1.10
15744  */
15745 ClutterActor *
15746 clutter_actor_get_child_at_index (ClutterActor *self,
15747                                   gint          index_)
15748 {
15749   ClutterActor *iter;
15750   int i;
15751
15752   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15753   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15754
15755   for (iter = self->priv->first_child, i = 0;
15756        iter != NULL && i < index_;
15757        iter = iter->priv->next_sibling, i += 1)
15758     ;
15759
15760   return iter;
15761 }
15762
15763 /*< private >
15764  * _clutter_actor_foreach_child:
15765  * @actor: The actor whos children you want to iterate
15766  * @callback: The function to call for each child
15767  * @user_data: Private data to pass to @callback
15768  *
15769  * Calls a given @callback once for each child of the specified @actor and
15770  * passing the @user_data pointer each time.
15771  *
15772  * Return value: returns %TRUE if all children were iterated, else
15773  *    %FALSE if a callback broke out of iteration early.
15774  */
15775 gboolean
15776 _clutter_actor_foreach_child (ClutterActor           *self,
15777                               ClutterForeachCallback  callback,
15778                               gpointer                user_data)
15779 {
15780   ClutterActor *iter;
15781   gboolean cont;
15782
15783   if (self->priv->first_child == NULL)
15784     return TRUE;
15785
15786   cont = TRUE;
15787   iter = self->priv->first_child;
15788
15789   /* we use this form so that it's safe to change the children
15790    * list while iterating it
15791    */
15792   while (cont && iter != NULL)
15793     {
15794       ClutterActor *next = iter->priv->next_sibling;
15795
15796       cont = callback (iter, user_data);
15797
15798       iter = next;
15799     }
15800
15801   return cont;
15802 }
15803
15804 #if 0
15805 /* For debugging purposes this gives us a simple way to print out
15806  * the scenegraph e.g in gdb using:
15807  * [|
15808  *   _clutter_actor_traverse (stage,
15809  *                            0,
15810  *                            clutter_debug_print_actor_cb,
15811  *                            NULL,
15812  *                            NULL);
15813  * |]
15814  */
15815 static ClutterActorTraverseVisitFlags
15816 clutter_debug_print_actor_cb (ClutterActor *actor,
15817                               int depth,
15818                               void *user_data)
15819 {
15820   g_print ("%*s%s:%p\n",
15821            depth * 2, "",
15822            _clutter_actor_get_debug_name (actor),
15823            actor);
15824
15825   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15826 }
15827 #endif
15828
15829 static void
15830 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15831                                  ClutterTraverseCallback callback,
15832                                  gpointer                user_data)
15833 {
15834   GQueue *queue = g_queue_new ();
15835   ClutterActor dummy;
15836   int current_depth = 0;
15837
15838   g_queue_push_tail (queue, actor);
15839   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15840
15841   while ((actor = g_queue_pop_head (queue)))
15842     {
15843       ClutterActorTraverseVisitFlags flags;
15844
15845       if (actor == &dummy)
15846         {
15847           current_depth++;
15848           g_queue_push_tail (queue, &dummy);
15849           continue;
15850         }
15851
15852       flags = callback (actor, current_depth, user_data);
15853       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15854         break;
15855       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15856         {
15857           ClutterActor *iter;
15858
15859           for (iter = actor->priv->first_child;
15860                iter != NULL;
15861                iter = iter->priv->next_sibling)
15862             {
15863               g_queue_push_tail (queue, iter);
15864             }
15865         }
15866     }
15867
15868   g_queue_free (queue);
15869 }
15870
15871 static ClutterActorTraverseVisitFlags
15872 _clutter_actor_traverse_depth (ClutterActor           *actor,
15873                                ClutterTraverseCallback before_children_callback,
15874                                ClutterTraverseCallback after_children_callback,
15875                                int                     current_depth,
15876                                gpointer                user_data)
15877 {
15878   ClutterActorTraverseVisitFlags flags;
15879
15880   flags = before_children_callback (actor, current_depth, user_data);
15881   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15882     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15883
15884   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15885     {
15886       ClutterActor *iter;
15887
15888       for (iter = actor->priv->first_child;
15889            iter != NULL;
15890            iter = iter->priv->next_sibling)
15891         {
15892           flags = _clutter_actor_traverse_depth (iter,
15893                                                  before_children_callback,
15894                                                  after_children_callback,
15895                                                  current_depth + 1,
15896                                                  user_data);
15897
15898           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15899             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15900         }
15901     }
15902
15903   if (after_children_callback)
15904     return after_children_callback (actor, current_depth, user_data);
15905   else
15906     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15907 }
15908
15909 /* _clutter_actor_traverse:
15910  * @actor: The actor to start traversing the graph from
15911  * @flags: These flags may affect how the traversal is done
15912  * @before_children_callback: A function to call before visiting the
15913  *   children of the current actor.
15914  * @after_children_callback: A function to call after visiting the
15915  *   children of the current actor. (Ignored if
15916  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15917  * @user_data: The private data to pass to the callbacks
15918  *
15919  * Traverses the scenegraph starting at the specified @actor and
15920  * descending through all its children and its children's children.
15921  * For each actor traversed @before_children_callback and
15922  * @after_children_callback are called with the specified
15923  * @user_data, before and after visiting that actor's children.
15924  *
15925  * The callbacks can return flags that affect the ongoing traversal
15926  * such as by skipping over an actors children or bailing out of
15927  * any further traversing.
15928  */
15929 void
15930 _clutter_actor_traverse (ClutterActor              *actor,
15931                          ClutterActorTraverseFlags  flags,
15932                          ClutterTraverseCallback    before_children_callback,
15933                          ClutterTraverseCallback    after_children_callback,
15934                          gpointer                   user_data)
15935 {
15936   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15937     _clutter_actor_traverse_breadth (actor,
15938                                      before_children_callback,
15939                                      user_data);
15940   else /* DEPTH_FIRST */
15941     _clutter_actor_traverse_depth (actor,
15942                                    before_children_callback,
15943                                    after_children_callback,
15944                                    0, /* start depth */
15945                                    user_data);
15946 }
15947
15948 static void
15949 on_layout_manager_changed (ClutterLayoutManager *manager,
15950                            ClutterActor         *self)
15951 {
15952   clutter_actor_queue_relayout (self);
15953 }
15954
15955 /**
15956  * clutter_actor_set_layout_manager:
15957  * @self: a #ClutterActor
15958  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15959  *
15960  * Sets the #ClutterLayoutManager delegate object that will be used to
15961  * lay out the children of @self.
15962  *
15963  * The #ClutterActor will take a reference on the passed @manager which
15964  * will be released either when the layout manager is removed, or when
15965  * the actor is destroyed.
15966  *
15967  * Since: 1.10
15968  */
15969 void
15970 clutter_actor_set_layout_manager (ClutterActor         *self,
15971                                   ClutterLayoutManager *manager)
15972 {
15973   ClutterActorPrivate *priv;
15974
15975   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15976   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
15977
15978   priv = self->priv;
15979
15980   if (priv->layout_manager != NULL)
15981     {
15982       g_signal_handlers_disconnect_by_func (priv->layout_manager,
15983                                             G_CALLBACK (on_layout_manager_changed),
15984                                             self);
15985       clutter_layout_manager_set_container (priv->layout_manager, NULL);
15986       g_clear_object (&priv->layout_manager);
15987     }
15988
15989   priv->layout_manager = manager;
15990
15991   if (priv->layout_manager != NULL)
15992     {
15993       g_object_ref_sink (priv->layout_manager);
15994       clutter_layout_manager_set_container (priv->layout_manager,
15995                                             CLUTTER_CONTAINER (self));
15996       g_signal_connect (priv->layout_manager, "layout-changed",
15997                         G_CALLBACK (on_layout_manager_changed),
15998                         self);
15999     }
16000
16001   clutter_actor_queue_relayout (self);
16002
16003   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16004 }
16005
16006 /**
16007  * clutter_actor_get_layout_manager:
16008  * @self: a #ClutterActor
16009  *
16010  * Retrieves the #ClutterLayoutManager used by @self.
16011  *
16012  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16013  *   or %NULL
16014  *
16015  * Since: 1.10
16016  */
16017 ClutterLayoutManager *
16018 clutter_actor_get_layout_manager (ClutterActor *self)
16019 {
16020   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16021
16022   return self->priv->layout_manager;
16023 }
16024
16025 static const ClutterLayoutInfo default_layout_info = {
16026   CLUTTER_POINT_INIT_ZERO,      /* fixed-pos */
16027   { 0, 0, 0, 0 },               /* margin */
16028   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
16029   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
16030   CLUTTER_SIZE_INIT_ZERO,       /* minimum */
16031   CLUTTER_SIZE_INIT_ZERO,       /* natural */
16032 };
16033
16034 static void
16035 layout_info_free (gpointer data)
16036 {
16037   if (G_LIKELY (data != NULL))
16038     g_slice_free (ClutterLayoutInfo, data);
16039 }
16040
16041 /*< private >
16042  * _clutter_actor_get_layout_info:
16043  * @self: a #ClutterActor
16044  *
16045  * Retrieves a pointer to the ClutterLayoutInfo structure.
16046  *
16047  * If the actor does not have a ClutterLayoutInfo associated to it, one
16048  * will be created and initialized to the default values.
16049  *
16050  * This function should be used for setters.
16051  *
16052  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16053  * instead.
16054  *
16055  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16056  */
16057 ClutterLayoutInfo *
16058 _clutter_actor_get_layout_info (ClutterActor *self)
16059 {
16060   ClutterLayoutInfo *retval;
16061
16062   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16063   if (retval == NULL)
16064     {
16065       retval = g_slice_new (ClutterLayoutInfo);
16066
16067       *retval = default_layout_info;
16068
16069       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16070                                retval,
16071                                layout_info_free);
16072     }
16073
16074   return retval;
16075 }
16076
16077 /*< private >
16078  * _clutter_actor_get_layout_info_or_defaults:
16079  * @self: a #ClutterActor
16080  *
16081  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16082  *
16083  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16084  * then the default structure will be returned.
16085  *
16086  * This function should only be used for getters.
16087  *
16088  * Return value: a const pointer to the ClutterLayoutInfo structure
16089  */
16090 const ClutterLayoutInfo *
16091 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16092 {
16093   const ClutterLayoutInfo *info;
16094
16095   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16096   if (info == NULL)
16097     return &default_layout_info;
16098
16099   return info;
16100 }
16101
16102 /**
16103  * clutter_actor_set_x_align:
16104  * @self: a #ClutterActor
16105  * @x_align: the horizontal alignment policy
16106  *
16107  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16108  * actor received extra horizontal space.
16109  *
16110  * See also the #ClutterActor:x-align property.
16111  *
16112  * Since: 1.10
16113  */
16114 void
16115 clutter_actor_set_x_align (ClutterActor      *self,
16116                            ClutterActorAlign  x_align)
16117 {
16118   ClutterLayoutInfo *info;
16119
16120   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16121
16122   info = _clutter_actor_get_layout_info (self);
16123
16124   if (info->x_align != x_align)
16125     {
16126       info->x_align = x_align;
16127
16128       clutter_actor_queue_relayout (self);
16129
16130       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16131     }
16132 }
16133
16134 /**
16135  * clutter_actor_get_x_align:
16136  * @self: a #ClutterActor
16137  *
16138  * Retrieves the horizontal alignment policy set using
16139  * clutter_actor_set_x_align().
16140  *
16141  * Return value: the horizontal alignment policy.
16142  *
16143  * Since: 1.10
16144  */
16145 ClutterActorAlign
16146 clutter_actor_get_x_align (ClutterActor *self)
16147 {
16148   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16149
16150   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16151 }
16152
16153 /**
16154  * clutter_actor_set_y_align:
16155  * @self: a #ClutterActor
16156  * @y_align: the vertical alignment policy
16157  *
16158  * Sets the vertical alignment policy of a #ClutterActor, in case the
16159  * actor received extra vertical space.
16160  *
16161  * See also the #ClutterActor:y-align property.
16162  *
16163  * Since: 1.10
16164  */
16165 void
16166 clutter_actor_set_y_align (ClutterActor      *self,
16167                            ClutterActorAlign  y_align)
16168 {
16169   ClutterLayoutInfo *info;
16170
16171   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16172
16173   info = _clutter_actor_get_layout_info (self);
16174
16175   if (info->y_align != y_align)
16176     {
16177       info->y_align = y_align;
16178
16179       clutter_actor_queue_relayout (self);
16180
16181       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16182     }
16183 }
16184
16185 /**
16186  * clutter_actor_get_y_align:
16187  * @self: a #ClutterActor
16188  *
16189  * Retrieves the vertical alignment policy set using
16190  * clutter_actor_set_y_align().
16191  *
16192  * Return value: the vertical alignment policy.
16193  *
16194  * Since: 1.10
16195  */
16196 ClutterActorAlign
16197 clutter_actor_get_y_align (ClutterActor *self)
16198 {
16199   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16200
16201   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16202 }
16203
16204 /**
16205  * clutter_actor_set_margin:
16206  * @self: a #ClutterActor
16207  * @margin: a #ClutterMargin
16208  *
16209  * Sets all the components of the margin of a #ClutterActor.
16210  *
16211  * Since: 1.10
16212  */
16213 void
16214 clutter_actor_set_margin (ClutterActor        *self,
16215                           const ClutterMargin *margin)
16216 {
16217   ClutterLayoutInfo *info;
16218   gboolean changed;
16219   GObject *obj;
16220
16221   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16222   g_return_if_fail (margin != NULL);
16223
16224   obj = G_OBJECT (self);
16225   changed = FALSE;
16226
16227   g_object_freeze_notify (obj);
16228
16229   info = _clutter_actor_get_layout_info (self);
16230
16231   if (info->margin.top != margin->top)
16232     {
16233       info->margin.top = margin->top;
16234       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16235       changed = TRUE;
16236     }
16237
16238   if (info->margin.right != margin->right)
16239     {
16240       info->margin.right = margin->right;
16241       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16242       changed = TRUE;
16243     }
16244
16245   if (info->margin.bottom != margin->bottom)
16246     {
16247       info->margin.bottom = margin->bottom;
16248       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16249       changed = TRUE;
16250     }
16251
16252   if (info->margin.left != margin->left)
16253     {
16254       info->margin.left = margin->left;
16255       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16256       changed = TRUE;
16257     }
16258
16259   if (changed)
16260     clutter_actor_queue_relayout (self);
16261
16262   g_object_thaw_notify (obj);
16263 }
16264
16265 /**
16266  * clutter_actor_get_margin:
16267  * @self: a #ClutterActor
16268  * @margin: (out caller-allocates): return location for a #ClutterMargin
16269  *
16270  * Retrieves all the components of the margin of a #ClutterActor.
16271  *
16272  * Since: 1.10
16273  */
16274 void
16275 clutter_actor_get_margin (ClutterActor  *self,
16276                           ClutterMargin *margin)
16277 {
16278   const ClutterLayoutInfo *info;
16279
16280   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16281   g_return_if_fail (margin != NULL);
16282
16283   info = _clutter_actor_get_layout_info_or_defaults (self);
16284
16285   *margin = info->margin;
16286 }
16287
16288 /**
16289  * clutter_actor_set_margin_top:
16290  * @self: a #ClutterActor
16291  * @margin: the top margin
16292  *
16293  * Sets the margin from the top of a #ClutterActor.
16294  *
16295  * Since: 1.10
16296  */
16297 void
16298 clutter_actor_set_margin_top (ClutterActor *self,
16299                               gfloat        margin)
16300 {
16301   ClutterLayoutInfo *info;
16302
16303   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16304   g_return_if_fail (margin >= 0.f);
16305
16306   info = _clutter_actor_get_layout_info (self);
16307
16308   if (info->margin.top == margin)
16309     return;
16310
16311   info->margin.top = margin;
16312
16313   clutter_actor_queue_relayout (self);
16314
16315   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16316 }
16317
16318 /**
16319  * clutter_actor_get_margin_top:
16320  * @self: a #ClutterActor
16321  *
16322  * Retrieves the top margin of a #ClutterActor.
16323  *
16324  * Return value: the top margin
16325  *
16326  * Since: 1.10
16327  */
16328 gfloat
16329 clutter_actor_get_margin_top (ClutterActor *self)
16330 {
16331   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16332
16333   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16334 }
16335
16336 /**
16337  * clutter_actor_set_margin_bottom:
16338  * @self: a #ClutterActor
16339  * @margin: the bottom margin
16340  *
16341  * Sets the margin from the bottom of a #ClutterActor.
16342  *
16343  * Since: 1.10
16344  */
16345 void
16346 clutter_actor_set_margin_bottom (ClutterActor *self,
16347                                  gfloat        margin)
16348 {
16349   ClutterLayoutInfo *info;
16350
16351   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16352   g_return_if_fail (margin >= 0.f);
16353
16354   info = _clutter_actor_get_layout_info (self);
16355
16356   if (info->margin.bottom == margin)
16357     return;
16358
16359   info->margin.bottom = margin;
16360
16361   clutter_actor_queue_relayout (self);
16362
16363   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16364 }
16365
16366 /**
16367  * clutter_actor_get_margin_bottom:
16368  * @self: a #ClutterActor
16369  *
16370  * Retrieves the bottom margin of a #ClutterActor.
16371  *
16372  * Return value: the bottom margin
16373  *
16374  * Since: 1.10
16375  */
16376 gfloat
16377 clutter_actor_get_margin_bottom (ClutterActor *self)
16378 {
16379   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16380
16381   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16382 }
16383
16384 /**
16385  * clutter_actor_set_margin_left:
16386  * @self: a #ClutterActor
16387  * @margin: the left margin
16388  *
16389  * Sets the margin from the left of a #ClutterActor.
16390  *
16391  * Since: 1.10
16392  */
16393 void
16394 clutter_actor_set_margin_left (ClutterActor *self,
16395                                gfloat        margin)
16396 {
16397   ClutterLayoutInfo *info;
16398
16399   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16400   g_return_if_fail (margin >= 0.f);
16401
16402   info = _clutter_actor_get_layout_info (self);
16403
16404   if (info->margin.left == margin)
16405     return;
16406
16407   info->margin.left = margin;
16408
16409   clutter_actor_queue_relayout (self);
16410
16411   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16412 }
16413
16414 /**
16415  * clutter_actor_get_margin_left:
16416  * @self: a #ClutterActor
16417  *
16418  * Retrieves the left margin of a #ClutterActor.
16419  *
16420  * Return value: the left margin
16421  *
16422  * Since: 1.10
16423  */
16424 gfloat
16425 clutter_actor_get_margin_left (ClutterActor *self)
16426 {
16427   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16428
16429   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16430 }
16431
16432 /**
16433  * clutter_actor_set_margin_right:
16434  * @self: a #ClutterActor
16435  * @margin: the right margin
16436  *
16437  * Sets the margin from the right of a #ClutterActor.
16438  *
16439  * Since: 1.10
16440  */
16441 void
16442 clutter_actor_set_margin_right (ClutterActor *self,
16443                                 gfloat        margin)
16444 {
16445   ClutterLayoutInfo *info;
16446
16447   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16448   g_return_if_fail (margin >= 0.f);
16449
16450   info = _clutter_actor_get_layout_info (self);
16451
16452   if (info->margin.right == margin)
16453     return;
16454
16455   info->margin.right = margin;
16456
16457   clutter_actor_queue_relayout (self);
16458
16459   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16460 }
16461
16462 /**
16463  * clutter_actor_get_margin_right:
16464  * @self: a #ClutterActor
16465  *
16466  * Retrieves the right margin of a #ClutterActor.
16467  *
16468  * Return value: the right margin
16469  *
16470  * Since: 1.10
16471  */
16472 gfloat
16473 clutter_actor_get_margin_right (ClutterActor *self)
16474 {
16475   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16476
16477   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16478 }
16479
16480 static inline void
16481 clutter_actor_set_background_color_internal (ClutterActor *self,
16482                                              const ClutterColor *color)
16483 {
16484   ClutterActorPrivate *priv = self->priv;
16485   GObject *obj;
16486
16487   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16488     return;
16489
16490   obj = G_OBJECT (self);
16491
16492   priv->bg_color = *color;
16493   priv->bg_color_set = TRUE;
16494
16495   clutter_actor_queue_redraw (self);
16496
16497   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16498   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16499 }
16500
16501 /**
16502  * clutter_actor_set_background_color:
16503  * @self: a #ClutterActor
16504  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16505  *  set color
16506  *
16507  * Sets the background color of a #ClutterActor.
16508  *
16509  * The background color will be used to cover the whole allocation of the
16510  * actor. The default background color of an actor is transparent.
16511  *
16512  * To check whether an actor has a background color, you can use the
16513  * #ClutterActor:background-color-set actor property.
16514  *
16515  * The #ClutterActor:background-color property is animatable.
16516  *
16517  * Since: 1.10
16518  */
16519 void
16520 clutter_actor_set_background_color (ClutterActor       *self,
16521                                     const ClutterColor *color)
16522 {
16523   ClutterActorPrivate *priv;
16524   GObject *obj;
16525   GParamSpec *bg_color_pspec;
16526
16527   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16528
16529   obj = G_OBJECT (self);
16530
16531   priv = self->priv;
16532
16533   if (color == NULL)
16534     {
16535       priv->bg_color_set = FALSE;
16536       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16537       clutter_actor_queue_redraw (self);
16538       return;
16539     }
16540
16541   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16542   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16543     {
16544       _clutter_actor_create_transition (self, bg_color_pspec,
16545                                         &priv->bg_color,
16546                                         color);
16547     }
16548   else
16549     _clutter_actor_update_transition (self, bg_color_pspec, color);
16550
16551   clutter_actor_queue_redraw (self);
16552 }
16553
16554 /**
16555  * clutter_actor_get_background_color:
16556  * @self: a #ClutterActor
16557  * @color: (out caller-allocates): return location for a #ClutterColor
16558  *
16559  * Retrieves the color set using clutter_actor_set_background_color().
16560  *
16561  * Since: 1.10
16562  */
16563 void
16564 clutter_actor_get_background_color (ClutterActor *self,
16565                                     ClutterColor *color)
16566 {
16567   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16568   g_return_if_fail (color != NULL);
16569
16570   *color = self->priv->bg_color;
16571 }
16572
16573 /**
16574  * clutter_actor_get_previous_sibling:
16575  * @self: a #ClutterActor
16576  *
16577  * Retrieves the sibling of @self that comes before it in the list
16578  * of children of @self's parent.
16579  *
16580  * The returned pointer is only valid until the scene graph changes; it
16581  * is not safe to modify the list of children of @self while iterating
16582  * it.
16583  *
16584  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16585  *
16586  * Since: 1.10
16587  */
16588 ClutterActor *
16589 clutter_actor_get_previous_sibling (ClutterActor *self)
16590 {
16591   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16592
16593   return self->priv->prev_sibling;
16594 }
16595
16596 /**
16597  * clutter_actor_get_next_sibling:
16598  * @self: a #ClutterActor
16599  *
16600  * Retrieves the sibling of @self that comes after it in the list
16601  * of children of @self's parent.
16602  *
16603  * The returned pointer is only valid until the scene graph changes; it
16604  * is not safe to modify the list of children of @self while iterating
16605  * it.
16606  *
16607  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16608  *
16609  * Since: 1.10
16610  */
16611 ClutterActor *
16612 clutter_actor_get_next_sibling (ClutterActor *self)
16613 {
16614   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16615
16616   return self->priv->next_sibling;
16617 }
16618
16619 /**
16620  * clutter_actor_get_first_child:
16621  * @self: a #ClutterActor
16622  *
16623  * Retrieves the first child of @self.
16624  *
16625  * The returned pointer is only valid until the scene graph changes; it
16626  * is not safe to modify the list of children of @self while iterating
16627  * it.
16628  *
16629  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16630  *
16631  * Since: 1.10
16632  */
16633 ClutterActor *
16634 clutter_actor_get_first_child (ClutterActor *self)
16635 {
16636   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16637
16638   return self->priv->first_child;
16639 }
16640
16641 /**
16642  * clutter_actor_get_last_child:
16643  * @self: a #ClutterActor
16644  *
16645  * Retrieves the last child of @self.
16646  *
16647  * The returned pointer is only valid until the scene graph changes; it
16648  * is not safe to modify the list of children of @self while iterating
16649  * it.
16650  *
16651  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16652  *
16653  * Since: 1.10
16654  */
16655 ClutterActor *
16656 clutter_actor_get_last_child (ClutterActor *self)
16657 {
16658   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16659
16660   return self->priv->last_child;
16661 }
16662
16663 /* easy way to have properly named fields instead of the dummy ones
16664  * we use in the public structure
16665  */
16666 typedef struct _RealActorIter
16667 {
16668   ClutterActor *root;           /* dummy1 */
16669   ClutterActor *current;        /* dummy2 */
16670   gpointer padding_1;           /* dummy3 */
16671   gint age;                     /* dummy4 */
16672   gpointer padding_2;           /* dummy5 */
16673 } RealActorIter;
16674
16675 /**
16676  * clutter_actor_iter_init:
16677  * @iter: a #ClutterActorIter
16678  * @root: a #ClutterActor
16679  *
16680  * Initializes a #ClutterActorIter, which can then be used to iterate
16681  * efficiently over a section of the scene graph, and associates it
16682  * with @root.
16683  *
16684  * Modifying the scene graph section that contains @root will invalidate
16685  * the iterator.
16686  *
16687  * |[
16688  *   ClutterActorIter iter;
16689  *   ClutterActor *child;
16690  *
16691  *   clutter_actor_iter_init (&iter, container);
16692  *   while (clutter_actor_iter_next (&iter, &child))
16693  *     {
16694  *       /&ast; do something with child &ast;/
16695  *     }
16696  * ]|
16697  *
16698  * Since: 1.10
16699  */
16700 void
16701 clutter_actor_iter_init (ClutterActorIter *iter,
16702                          ClutterActor     *root)
16703 {
16704   RealActorIter *ri = (RealActorIter *) iter;
16705
16706   g_return_if_fail (iter != NULL);
16707   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16708
16709   ri->root = root;
16710   ri->current = NULL;
16711   ri->age = root->priv->age;
16712 }
16713
16714 /**
16715  * clutter_actor_iter_next:
16716  * @iter: a #ClutterActorIter
16717  * @child: (out): return location for a #ClutterActor
16718  *
16719  * Advances the @iter and retrieves the next child of the root #ClutterActor
16720  * that was used to initialize the #ClutterActorIterator.
16721  *
16722  * If the iterator can advance, this function returns %TRUE and sets the
16723  * @child argument.
16724  *
16725  * If the iterator cannot advance, this function returns %FALSE, and
16726  * the contents of @child are undefined.
16727  *
16728  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16729  *
16730  * Since: 1.10
16731  */
16732 gboolean
16733 clutter_actor_iter_next (ClutterActorIter  *iter,
16734                          ClutterActor     **child)
16735 {
16736   RealActorIter *ri = (RealActorIter *) iter;
16737
16738   g_return_val_if_fail (iter != NULL, FALSE);
16739   g_return_val_if_fail (ri->root != NULL, FALSE);
16740 #ifndef G_DISABLE_ASSERT
16741   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16742 #endif
16743
16744   if (ri->current == NULL)
16745     ri->current = ri->root->priv->first_child;
16746   else
16747     ri->current = ri->current->priv->next_sibling;
16748
16749   if (child != NULL)
16750     *child = ri->current;
16751
16752   return ri->current != NULL;
16753 }
16754
16755 /**
16756  * clutter_actor_iter_prev:
16757  * @iter: a #ClutterActorIter
16758  * @child: (out): return location for a #ClutterActor
16759  *
16760  * Advances the @iter and retrieves the previous child of the root
16761  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16762  *
16763  * If the iterator can advance, this function returns %TRUE and sets the
16764  * @child argument.
16765  *
16766  * If the iterator cannot advance, this function returns %FALSE, and
16767  * the contents of @child are undefined.
16768  *
16769  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16770  *
16771  * Since: 1.10
16772  */
16773 gboolean
16774 clutter_actor_iter_prev (ClutterActorIter  *iter,
16775                          ClutterActor     **child)
16776 {
16777   RealActorIter *ri = (RealActorIter *) iter;
16778
16779   g_return_val_if_fail (iter != NULL, FALSE);
16780   g_return_val_if_fail (ri->root != NULL, FALSE);
16781 #ifndef G_DISABLE_ASSERT
16782   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16783 #endif
16784
16785   if (ri->current == NULL)
16786     ri->current = ri->root->priv->last_child;
16787   else
16788     ri->current = ri->current->priv->prev_sibling;
16789
16790   if (child != NULL)
16791     *child = ri->current;
16792
16793   return ri->current != NULL;
16794 }
16795
16796 /**
16797  * clutter_actor_iter_remove:
16798  * @iter: a #ClutterActorIter
16799  *
16800  * Safely removes the #ClutterActor currently pointer to by the iterator
16801  * from its parent.
16802  *
16803  * This function can only be called after clutter_actor_iter_next() or
16804  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16805  * than once for the same actor.
16806  *
16807  * This function will call clutter_actor_remove_child() internally.
16808  *
16809  * Since: 1.10
16810  */
16811 void
16812 clutter_actor_iter_remove (ClutterActorIter *iter)
16813 {
16814   RealActorIter *ri = (RealActorIter *) iter;
16815   ClutterActor *cur;
16816
16817   g_return_if_fail (iter != NULL);
16818   g_return_if_fail (ri->root != NULL);
16819 #ifndef G_DISABLE_ASSERT
16820   g_return_if_fail (ri->age == ri->root->priv->age);
16821 #endif
16822   g_return_if_fail (ri->current != NULL);
16823
16824   cur = ri->current;
16825
16826   if (cur != NULL)
16827     {
16828       ri->current = cur->priv->prev_sibling;
16829
16830       clutter_actor_remove_child_internal (ri->root, cur,
16831                                            REMOVE_CHILD_DEFAULT_FLAGS);
16832
16833       ri->age += 1;
16834     }
16835 }
16836
16837 /**
16838  * clutter_actor_iter_destroy:
16839  * @iter: a #ClutterActorIter
16840  *
16841  * Safely destroys the #ClutterActor currently pointer to by the iterator
16842  * from its parent.
16843  *
16844  * This function can only be called after clutter_actor_iter_next() or
16845  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16846  * than once for the same actor.
16847  *
16848  * This function will call clutter_actor_destroy() internally.
16849  *
16850  * Since: 1.10
16851  */
16852 void
16853 clutter_actor_iter_destroy (ClutterActorIter *iter)
16854 {
16855   RealActorIter *ri = (RealActorIter *) iter;
16856   ClutterActor *cur;
16857
16858   g_return_if_fail (iter != NULL);
16859   g_return_if_fail (ri->root != NULL);
16860 #ifndef G_DISABLE_ASSERT
16861   g_return_if_fail (ri->age == ri->root->priv->age);
16862 #endif
16863   g_return_if_fail (ri->current != NULL);
16864
16865   cur = ri->current;
16866
16867   if (cur != NULL)
16868     {
16869       ri->current = cur->priv->prev_sibling;
16870
16871       clutter_actor_destroy (cur);
16872
16873       ri->age += 1;
16874     }
16875 }
16876
16877 static const ClutterAnimationInfo default_animation_info = {
16878   NULL,         /* transitions */
16879   NULL,         /* states */
16880   NULL,         /* cur_state */
16881 };
16882
16883 static void
16884 clutter_animation_info_free (gpointer data)
16885 {
16886   if (data != NULL)
16887     {
16888       ClutterAnimationInfo *info = data;
16889
16890       if (info->transitions != NULL)
16891         g_hash_table_unref (info->transitions);
16892
16893       if (info->states != NULL)
16894         g_array_unref (info->states);
16895
16896       g_slice_free (ClutterAnimationInfo, info);
16897     }
16898 }
16899
16900 const ClutterAnimationInfo *
16901 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16902 {
16903   const ClutterAnimationInfo *res;
16904   GObject *obj = G_OBJECT (self);
16905
16906   res = g_object_get_qdata (obj, quark_actor_animation_info);
16907   if (res != NULL)
16908     return res;
16909
16910   return &default_animation_info;
16911 }
16912
16913 ClutterAnimationInfo *
16914 _clutter_actor_get_animation_info (ClutterActor *self)
16915 {
16916   GObject *obj = G_OBJECT (self);
16917   ClutterAnimationInfo *res;
16918
16919   res = g_object_get_qdata (obj, quark_actor_animation_info);
16920   if (res == NULL)
16921     {
16922       res = g_slice_new (ClutterAnimationInfo);
16923
16924       *res = default_animation_info;
16925
16926       g_object_set_qdata_full (obj, quark_actor_animation_info,
16927                                res,
16928                                clutter_animation_info_free);
16929     }
16930
16931   return res;
16932 }
16933
16934 ClutterTransition *
16935 _clutter_actor_get_transition (ClutterActor *actor,
16936                                GParamSpec   *pspec)
16937 {
16938   const ClutterAnimationInfo *info;
16939
16940   info = _clutter_actor_get_animation_info_or_defaults (actor);
16941
16942   if (info->transitions == NULL)
16943     return NULL;
16944
16945   return g_hash_table_lookup (info->transitions, pspec->name);
16946 }
16947
16948 typedef struct _TransitionClosure
16949 {
16950   ClutterActor *actor;
16951   ClutterTransition *transition;
16952   gchar *name;
16953   gulong completed_id;
16954 } TransitionClosure;
16955
16956 static void
16957 transition_closure_free (gpointer data)
16958 {
16959   if (G_LIKELY (data != NULL))
16960     {
16961       TransitionClosure *clos = data;
16962       ClutterTimeline *timeline;
16963
16964       timeline = CLUTTER_TIMELINE (clos->transition);
16965
16966       if (clutter_timeline_is_playing (timeline))
16967         clutter_timeline_stop (timeline);
16968
16969       g_signal_handler_disconnect (clos->transition, clos->completed_id);
16970
16971       g_object_unref (clos->transition);
16972       g_free (clos->name);
16973
16974       g_slice_free (TransitionClosure, clos);
16975     }
16976 }
16977
16978 static void
16979 on_transition_completed (ClutterTransition *transition,
16980                          TransitionClosure *clos)
16981 {
16982   ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
16983   ClutterActor *actor = clos->actor;
16984   ClutterAnimationInfo *info;
16985   gint n_repeats, cur_repeat;
16986
16987   info = _clutter_actor_get_animation_info (actor);
16988
16989   /* reset the caches used by animations */
16990   clutter_actor_store_content_box (actor, NULL);
16991
16992   /* ensure that we remove the transition only at the end
16993    * of its run; we emit ::completed for every repeat
16994    */
16995   n_repeats = clutter_timeline_get_repeat_count (timeline);
16996   cur_repeat = clutter_timeline_get_current_repeat (timeline);
16997
16998   if (cur_repeat == n_repeats)
16999     {
17000       if (clutter_transition_get_remove_on_complete (transition))
17001         {
17002           /* we take a reference here because removing the closure
17003            * will release the reference on the transition, and we
17004            * want the transition to survive the signal emission;
17005            * the master clock will release the last reference at
17006            * the end of the frame processing.
17007            */
17008           g_object_ref (transition);
17009           g_hash_table_remove (info->transitions, clos->name);
17010         }
17011     }
17012
17013   /* if it's the last transition then we clean up */
17014   if (g_hash_table_size (info->transitions) == 0)
17015     {
17016       g_hash_table_unref (info->transitions);
17017       info->transitions = NULL;
17018
17019       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17020                     _clutter_actor_get_debug_name (actor));
17021
17022       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17023     }
17024 }
17025
17026 void
17027 _clutter_actor_update_transition (ClutterActor *actor,
17028                                   GParamSpec   *pspec,
17029                                   ...)
17030 {
17031   TransitionClosure *clos;
17032   ClutterTimeline *timeline;
17033   ClutterInterval *interval;
17034   const ClutterAnimationInfo *info;
17035   va_list var_args;
17036   GType ptype;
17037   GValue initial = G_VALUE_INIT;
17038   GValue final = G_VALUE_INIT;
17039   char *error = NULL;
17040
17041   info = _clutter_actor_get_animation_info_or_defaults (actor);
17042
17043   if (info->transitions == NULL)
17044     return;
17045
17046   clos = g_hash_table_lookup (info->transitions, pspec->name);
17047   if (clos == NULL)
17048     return;
17049
17050   timeline = CLUTTER_TIMELINE (clos->transition);
17051
17052   va_start (var_args, pspec);
17053
17054   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17055
17056   g_value_init (&initial, ptype);
17057   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17058                                         pspec->name,
17059                                         &initial);
17060
17061   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17062   if (error != NULL)
17063     {
17064       g_critical ("%s: %s", G_STRLOC, error);
17065       g_free (error);
17066       goto out;
17067     }
17068
17069   interval = clutter_transition_get_interval (clos->transition);
17070   clutter_interval_set_initial_value (interval, &initial);
17071   clutter_interval_set_final_value (interval, &final);
17072
17073   /* if we're updating with an easing duration of zero milliseconds,
17074    * we just jump the timeline to the end and let it run its course
17075    */
17076   if (info->cur_state != NULL &&
17077       info->cur_state->easing_duration != 0)
17078     {
17079       guint cur_duration = clutter_timeline_get_duration (timeline);
17080       ClutterAnimationMode cur_mode =
17081         clutter_timeline_get_progress_mode (timeline);
17082
17083       if (cur_duration != info->cur_state->easing_duration)
17084         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17085
17086       if (cur_mode != info->cur_state->easing_mode)
17087         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17088
17089       clutter_timeline_rewind (timeline);
17090     }
17091   else
17092     {
17093       guint duration = clutter_timeline_get_duration (timeline);
17094
17095       clutter_timeline_advance (timeline, duration);
17096     }
17097
17098 out:
17099   g_value_unset (&initial);
17100   g_value_unset (&final);
17101
17102   va_end (var_args);
17103 }
17104
17105 /*< private >*
17106  * _clutter_actor_create_transition:
17107  * @actor: a #ClutterActor
17108  * @pspec: the property used for the transition
17109  * @...: initial and final state
17110  *
17111  * Creates a #ClutterTransition for the property represented by @pspec.
17112  *
17113  * Return value: a #ClutterTransition
17114  */
17115 ClutterTransition *
17116 _clutter_actor_create_transition (ClutterActor *actor,
17117                                   GParamSpec   *pspec,
17118                                   ...)
17119 {
17120   ClutterAnimationInfo *info;
17121   ClutterTransition *res = NULL;
17122   gboolean call_restore = FALSE;
17123   TransitionClosure *clos;
17124   va_list var_args;
17125
17126   info = _clutter_actor_get_animation_info (actor);
17127
17128   /* XXX - this will go away in 2.0
17129    *
17130    * if no state has been pushed, we assume that the easing state is
17131    * in "compatibility mode": all transitions have a duration of 0
17132    * msecs, which means that they happen immediately. in Clutter 2.0
17133    * this will turn into a g_assert(info->states != NULL), as every
17134    * actor will start with a predefined easing state
17135    */
17136   if (info->states == NULL)
17137     {
17138       clutter_actor_save_easing_state (actor);
17139       clutter_actor_set_easing_duration (actor, 0);
17140       call_restore = TRUE;
17141     }
17142
17143   if (info->transitions == NULL)
17144     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17145                                                NULL,
17146                                                transition_closure_free);
17147
17148   va_start (var_args, pspec);
17149
17150   clos = g_hash_table_lookup (info->transitions, pspec->name);
17151   if (clos == NULL)
17152     {
17153       ClutterInterval *interval;
17154       GValue initial = G_VALUE_INIT;
17155       GValue final = G_VALUE_INIT;
17156       GType ptype;
17157       char *error;
17158
17159       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17160
17161       G_VALUE_COLLECT_INIT (&initial, ptype,
17162                             var_args, 0,
17163                             &error);
17164       if (error != NULL)
17165         {
17166           g_critical ("%s: %s", G_STRLOC, error);
17167           g_free (error);
17168           goto out;
17169         }
17170
17171       G_VALUE_COLLECT_INIT (&final, ptype,
17172                             var_args, 0,
17173                             &error);
17174
17175       if (error != NULL)
17176         {
17177           g_critical ("%s: %s", G_STRLOC, error);
17178           g_value_unset (&initial);
17179           g_free (error);
17180           goto out;
17181         }
17182
17183       /* if the current easing state has a duration of 0, then we don't
17184        * bother to create the transition, and we just set the final value
17185        * directly on the actor; we don't go through the Animatable
17186        * interface because we know we got here through an animatable
17187        * property.
17188        */
17189       if (info->cur_state->easing_duration == 0)
17190         {
17191           clutter_actor_set_animatable_property (actor,
17192                                                  pspec->param_id,
17193                                                  &final,
17194                                                  pspec);
17195           g_value_unset (&initial);
17196           g_value_unset (&final);
17197
17198           goto out;
17199         }
17200
17201       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17202
17203       g_value_unset (&initial);
17204       g_value_unset (&final);
17205
17206       res = clutter_property_transition_new (pspec->name);
17207
17208       clutter_transition_set_interval (res, interval);
17209       clutter_transition_set_remove_on_complete (res, TRUE);
17210
17211       /* this will start the transition as well */
17212       clutter_actor_add_transition (actor, pspec->name, res);
17213
17214       /* the actor now owns the transition */
17215       g_object_unref (res);
17216     }
17217   else
17218     res = clos->transition;
17219
17220 out:
17221   if (call_restore)
17222     clutter_actor_restore_easing_state (actor);
17223
17224   va_end (var_args);
17225
17226   return res;
17227 }
17228
17229 /**
17230  * clutter_actor_add_transition:
17231  * @self: a #ClutterActor
17232  * @name: the name of the transition to add
17233  * @transition: the #ClutterTransition to add
17234  *
17235  * Adds a @transition to the #ClutterActor's list of animations.
17236  *
17237  * The @name string is a per-actor unique identifier of the @transition: only
17238  * one #ClutterTransition can be associated to the specified @name.
17239  *
17240  * The @transition will be given the easing duration, mode, and delay
17241  * associated to the actor's current easing state; it is possible to modify
17242  * these values after calling clutter_actor_add_transition().
17243  *
17244  * The @transition will be started once added.
17245  *
17246  * This function will take a reference on the @transition.
17247  *
17248  * This function is usually called implicitly when modifying an animatable
17249  * property.
17250  *
17251  * Since: 1.10
17252  */
17253 void
17254 clutter_actor_add_transition (ClutterActor      *self,
17255                               const char        *name,
17256                               ClutterTransition *transition)
17257 {
17258   ClutterTimeline *timeline;
17259   TransitionClosure *clos;
17260   ClutterAnimationInfo *info;
17261
17262   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17263   g_return_if_fail (name != NULL);
17264   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17265
17266   info = _clutter_actor_get_animation_info (self);
17267
17268   if (info->cur_state == NULL)
17269     {
17270       g_warning ("No easing state is defined for the actor '%s'; you "
17271                  "must call clutter_actor_save_easing_state() before "
17272                  "calling clutter_actor_add_transition().",
17273                  _clutter_actor_get_debug_name (self));
17274       return;
17275     }
17276
17277   if (info->transitions == NULL)
17278     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17279                                                NULL,
17280                                                transition_closure_free);
17281
17282   if (g_hash_table_lookup (info->transitions, name) != NULL)
17283     {
17284       g_warning ("A transition with name '%s' already exists for "
17285                  "the actor '%s'",
17286                  name,
17287                  _clutter_actor_get_debug_name (self));
17288       return;
17289     }
17290
17291   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17292
17293   timeline = CLUTTER_TIMELINE (transition);
17294
17295   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17296   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17297   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17298
17299   clos = g_slice_new (TransitionClosure);
17300   clos->actor = self;
17301   clos->transition = g_object_ref (transition);
17302   clos->name = g_strdup (name);
17303   clos->completed_id = g_signal_connect (timeline, "completed",
17304                                          G_CALLBACK (on_transition_completed),
17305                                          clos);
17306
17307   CLUTTER_NOTE (ANIMATION,
17308                 "Adding transition '%s' [%p] to actor '%s'",
17309                 clos->name,
17310                 clos->transition,
17311                 _clutter_actor_get_debug_name (self));
17312
17313   g_hash_table_insert (info->transitions, clos->name, clos);
17314   clutter_timeline_start (timeline);
17315 }
17316
17317 /**
17318  * clutter_actor_remove_transition:
17319  * @self: a #ClutterActor
17320  * @name: the name of the transition to remove
17321  *
17322  * Removes the transition stored inside a #ClutterActor using @name
17323  * identifier.
17324  *
17325  * If the transition is currently in progress, it will be stopped.
17326  *
17327  * This function releases the reference acquired when the transition
17328  * was added to the #ClutterActor.
17329  *
17330  * Since: 1.10
17331  */
17332 void
17333 clutter_actor_remove_transition (ClutterActor *self,
17334                                  const char   *name)
17335 {
17336   const ClutterAnimationInfo *info;
17337
17338   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17339   g_return_if_fail (name != NULL);
17340
17341   info = _clutter_actor_get_animation_info_or_defaults (self);
17342
17343   if (info->transitions == NULL)
17344     return;
17345
17346   g_hash_table_remove (info->transitions, name);
17347 }
17348
17349 /**
17350  * clutter_actor_remove_all_transitions:
17351  * @self: a #ClutterActor
17352  *
17353  * Removes all transitions associated to @self.
17354  *
17355  * Since: 1.10
17356  */
17357 void
17358 clutter_actor_remove_all_transitions (ClutterActor *self)
17359 {
17360   const ClutterAnimationInfo *info;
17361
17362   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17363
17364   info = _clutter_actor_get_animation_info_or_defaults (self);
17365   if (info->transitions == NULL)
17366     return;
17367
17368   g_hash_table_remove_all (info->transitions);
17369 }
17370
17371 /**
17372  * clutter_actor_set_easing_duration:
17373  * @self: a #ClutterActor
17374  * @msecs: the duration of the easing, or %NULL
17375  *
17376  * Sets the duration of the tweening for animatable properties
17377  * of @self for the current easing state.
17378  *
17379  * Since: 1.10
17380  */
17381 void
17382 clutter_actor_set_easing_duration (ClutterActor *self,
17383                                    guint         msecs)
17384 {
17385   ClutterAnimationInfo *info;
17386
17387   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17388
17389   info = _clutter_actor_get_animation_info (self);
17390
17391   if (info->cur_state == NULL)
17392     {
17393       g_warning ("You must call clutter_actor_save_easing_state() prior "
17394                  "to calling clutter_actor_set_easing_duration().");
17395       return;
17396     }
17397
17398   if (info->cur_state->easing_duration != msecs)
17399     info->cur_state->easing_duration = msecs;
17400 }
17401
17402 /**
17403  * clutter_actor_get_easing_duration:
17404  * @self: a #ClutterActor
17405  *
17406  * Retrieves the duration of the tweening for animatable
17407  * properties of @self for the current easing state.
17408  *
17409  * Return value: the duration of the tweening, in milliseconds
17410  *
17411  * Since: 1.10
17412  */
17413 guint
17414 clutter_actor_get_easing_duration (ClutterActor *self)
17415 {
17416   const ClutterAnimationInfo *info;
17417
17418   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17419
17420   info = _clutter_actor_get_animation_info_or_defaults (self);
17421
17422   if (info->cur_state != NULL)
17423     return info->cur_state->easing_duration;
17424
17425   return 0;
17426 }
17427
17428 /**
17429  * clutter_actor_set_easing_mode:
17430  * @self: a #ClutterActor
17431  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17432  *
17433  * Sets the easing mode for the tweening of animatable properties
17434  * of @self.
17435  *
17436  * Since: 1.10
17437  */
17438 void
17439 clutter_actor_set_easing_mode (ClutterActor         *self,
17440                                ClutterAnimationMode  mode)
17441 {
17442   ClutterAnimationInfo *info;
17443
17444   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17445   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17446   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17447
17448   info = _clutter_actor_get_animation_info (self);
17449
17450   if (info->cur_state == NULL)
17451     {
17452       g_warning ("You must call clutter_actor_save_easing_state() prior "
17453                  "to calling clutter_actor_set_easing_mode().");
17454       return;
17455     }
17456
17457   if (info->cur_state->easing_mode != mode)
17458     info->cur_state->easing_mode = mode;
17459 }
17460
17461 /**
17462  * clutter_actor_get_easing_mode:
17463  * @self: a #ClutterActor
17464  *
17465  * Retrieves the easing mode for the tweening of animatable properties
17466  * of @self for the current easing state.
17467  *
17468  * Return value: an easing mode
17469  *
17470  * Since: 1.10
17471  */
17472 ClutterAnimationMode
17473 clutter_actor_get_easing_mode (ClutterActor *self)
17474 {
17475   const ClutterAnimationInfo *info;
17476
17477   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17478
17479   info = _clutter_actor_get_animation_info_or_defaults (self);
17480
17481   if (info->cur_state != NULL)
17482     return info->cur_state->easing_mode;
17483
17484   return CLUTTER_EASE_OUT_CUBIC;
17485 }
17486
17487 /**
17488  * clutter_actor_set_easing_delay:
17489  * @self: a #ClutterActor
17490  * @msecs: the delay before the start of the tweening, in milliseconds
17491  *
17492  * Sets the delay that should be applied before tweening animatable
17493  * properties.
17494  *
17495  * Since: 1.10
17496  */
17497 void
17498 clutter_actor_set_easing_delay (ClutterActor *self,
17499                                 guint         msecs)
17500 {
17501   ClutterAnimationInfo *info;
17502
17503   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17504
17505   info = _clutter_actor_get_animation_info (self);
17506
17507   if (info->cur_state == NULL)
17508     {
17509       g_warning ("You must call clutter_actor_save_easing_state() prior "
17510                  "to calling clutter_actor_set_easing_delay().");
17511       return;
17512     }
17513
17514   if (info->cur_state->easing_delay != msecs)
17515     info->cur_state->easing_delay = msecs;
17516 }
17517
17518 /**
17519  * clutter_actor_get_easing_delay:
17520  * @self: a #ClutterActor
17521  *
17522  * Retrieves the delay that should be applied when tweening animatable
17523  * properties.
17524  *
17525  * Return value: a delay, in milliseconds
17526  *
17527  * Since: 1.10
17528  */
17529 guint
17530 clutter_actor_get_easing_delay (ClutterActor *self)
17531 {
17532   const ClutterAnimationInfo *info;
17533
17534   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17535
17536   info = _clutter_actor_get_animation_info_or_defaults (self);
17537
17538   if (info->cur_state != NULL)
17539     return info->cur_state->easing_delay;
17540
17541   return 0;
17542 }
17543
17544 /**
17545  * clutter_actor_get_transition:
17546  * @self: a #ClutterActor
17547  * @name: the name of the transition
17548  *
17549  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17550  * transition @name.
17551  *
17552  * Transitions created for animatable properties use the name of the
17553  * property itself, for instance the code below:
17554  *
17555  * |[
17556  *   clutter_actor_set_easing_duration (actor, 1000);
17557  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17558  *
17559  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17560  *   g_signal_connect (transition, "completed",
17561  *                     G_CALLBACK (on_transition_complete),
17562  *                     actor);
17563  * ]|
17564  *
17565  * will call the <function>on_transition_complete</function> callback when
17566  * the transition is complete.
17567  *
17568  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17569  *   was found to match the passed name; the returned instance is owned
17570  *   by Clutter and it should not be freed
17571  *
17572  * Since: 1.10
17573  */
17574 ClutterTransition *
17575 clutter_actor_get_transition (ClutterActor *self,
17576                               const char   *name)
17577 {
17578   TransitionClosure *clos;
17579   const ClutterAnimationInfo *info;
17580
17581   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17582   g_return_val_if_fail (name != NULL, NULL);
17583
17584   info = _clutter_actor_get_animation_info_or_defaults (self);
17585   if (info->transitions == NULL)
17586     return NULL;
17587
17588   clos = g_hash_table_lookup (info->transitions, name);
17589   if (clos == NULL)
17590     return NULL;
17591
17592   return clos->transition;
17593 }
17594
17595 /**
17596  * clutter_actor_save_easing_state:
17597  * @self: a #ClutterActor
17598  *
17599  * Saves the current easing state for animatable properties, and creates
17600  * a new state with the default values for easing mode and duration.
17601  *
17602  * Since: 1.10
17603  */
17604 void
17605 clutter_actor_save_easing_state (ClutterActor *self)
17606 {
17607   ClutterAnimationInfo *info;
17608   AState new_state;
17609
17610   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17611
17612   info = _clutter_actor_get_animation_info (self);
17613
17614   if (info->states == NULL)
17615     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17616
17617   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17618   new_state.easing_duration = 250;
17619   new_state.easing_delay = 0;
17620
17621   g_array_append_val (info->states, new_state);
17622
17623   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17624 }
17625
17626 /**
17627  * clutter_actor_restore_easing_state:
17628  * @self: a #ClutterActor
17629  *
17630  * Restores the easing state as it was prior to a call to
17631  * clutter_actor_save_easing_state().
17632  *
17633  * Since: 1.10
17634  */
17635 void
17636 clutter_actor_restore_easing_state (ClutterActor *self)
17637 {
17638   ClutterAnimationInfo *info;
17639
17640   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17641
17642   info = _clutter_actor_get_animation_info (self);
17643
17644   if (info->states == NULL)
17645     {
17646       g_critical ("The function clutter_actor_restore_easing_state() has "
17647                   "called without a previous call to "
17648                   "clutter_actor_save_easing_state().");
17649       return;
17650     }
17651
17652   g_array_remove_index (info->states, info->states->len - 1);
17653
17654   if (info->states->len > 0)
17655     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17656   else
17657     {
17658       g_array_unref (info->states);
17659       info->states = NULL;
17660       info->cur_state = NULL;
17661     }
17662 }
17663
17664 /**
17665  * clutter_actor_set_content:
17666  * @self: a #ClutterActor
17667  * @content: (allow-none): a #ClutterContent, or %NULL
17668  *
17669  * Sets the contents of a #ClutterActor.
17670  *
17671  * Since: 1.10
17672  */
17673 void
17674 clutter_actor_set_content (ClutterActor   *self,
17675                            ClutterContent *content)
17676 {
17677   ClutterActorPrivate *priv;
17678
17679   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17680   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17681
17682   priv = self->priv;
17683
17684   if (priv->content != NULL)
17685     {
17686       _clutter_content_detached (priv->content, self);
17687       g_clear_object (&priv->content);
17688     }
17689
17690   priv->content = content;
17691
17692   if (priv->content != NULL)
17693     {
17694       g_object_ref (priv->content);
17695       _clutter_content_attached (priv->content, self);
17696     }
17697
17698   /* given that the content is always painted within the allocation,
17699    * we only need to queue a redraw here
17700    */
17701   clutter_actor_queue_redraw (self);
17702
17703   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17704
17705   /* if the content gravity is not resize-fill, and the new content has a
17706    * different preferred size than the previous one, then the content box
17707    * may have been changed. since we compute that lazily, we just notify
17708    * here, and let whomever watches :content-box do whatever they need to
17709    * do.
17710    */
17711   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17712     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17713 }
17714
17715 /**
17716  * clutter_actor_get_content:
17717  * @self: a #ClutterActor
17718  *
17719  * Retrieves the contents of @self.
17720  *
17721  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17722  *   or %NULL if none was set
17723  *
17724  * Since: 1.10
17725  */
17726 ClutterContent *
17727 clutter_actor_get_content (ClutterActor *self)
17728 {
17729   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17730
17731   return self->priv->content;
17732 }
17733
17734 /**
17735  * clutter_actor_set_content_gravity:
17736  * @self: a #ClutterActor
17737  * @gravity: the #ClutterContentGravity
17738  *
17739  * Sets the gravity of the #ClutterContent used by @self.
17740  *
17741  * See the description of the #ClutterActor:content-gravity property for
17742  * more information.
17743  *
17744  * The #ClutterActor:content-gravity property is animatable.
17745  *
17746  * Since: 1.10
17747  */
17748 void
17749 clutter_actor_set_content_gravity (ClutterActor *self,
17750                                    ClutterContentGravity  gravity)
17751 {
17752   ClutterActorPrivate *priv;
17753
17754   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17755
17756   priv = self->priv;
17757
17758   if (priv->content_gravity == gravity)
17759     return;
17760
17761   priv->content_box_valid = FALSE;
17762
17763   if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17764     {
17765       ClutterActorBox from_box, to_box;
17766
17767       clutter_actor_get_content_box (self, &from_box);
17768
17769       priv->content_gravity = gravity;
17770
17771       clutter_actor_get_content_box (self, &to_box);
17772
17773       _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17774                                         &from_box,
17775                                         &to_box);
17776     }
17777   else
17778     {
17779       ClutterActorBox to_box;
17780
17781       priv->content_gravity = gravity;
17782
17783       clutter_actor_get_content_box (self, &to_box);
17784
17785       _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17786                                         &to_box);
17787     }
17788
17789   clutter_actor_queue_redraw (self);
17790
17791   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17792 }
17793
17794 /**
17795  * clutter_actor_get_content_gravity:
17796  * @self: a #ClutterActor
17797  *
17798  * Retrieves the content gravity as set using
17799  * clutter_actor_get_content_gravity().
17800  *
17801  * Return value: the content gravity
17802  *
17803  * Since: 1.10
17804  */
17805 ClutterContentGravity
17806 clutter_actor_get_content_gravity (ClutterActor *self)
17807 {
17808   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17809                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17810
17811   return self->priv->content_gravity;
17812 }
17813
17814 /**
17815  * clutter_actor_get_content_box:
17816  * @self: a #ClutterActor
17817  * @box: (out caller-allocates): the return location for the bounding
17818  *   box for the #ClutterContent
17819  *
17820  * Retrieves the bounding box for the #ClutterContent of @self.
17821  *
17822  * The bounding box is relative to the actor's allocation.
17823  *
17824  * If no #ClutterContent is set for @self, or if @self has not been
17825  * allocated yet, then the result is undefined.
17826  *
17827  * The content box is guaranteed to be, at most, as big as the allocation
17828  * of the #ClutterActor.
17829  *
17830  * If the #ClutterContent used by the actor has a preferred size, then
17831  * it is possible to modify the content box by using the
17832  * #ClutterActor:content-gravity property.
17833  *
17834  * Since: 1.10
17835  */
17836 void
17837 clutter_actor_get_content_box (ClutterActor    *self,
17838                                ClutterActorBox *box)
17839 {
17840   ClutterActorPrivate *priv;
17841   gfloat content_w, content_h;
17842   gfloat alloc_w, alloc_h;
17843
17844   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17845   g_return_if_fail (box != NULL);
17846
17847   priv = self->priv;
17848
17849   box->x1 = 0.f;
17850   box->y1 = 0.f;
17851   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17852   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17853
17854   if (priv->content_box_valid)
17855     {
17856       *box = priv->content_box;
17857       return;
17858     }
17859
17860   /* no need to do any more work */
17861   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17862     return;
17863
17864   if (priv->content == NULL)
17865     return;
17866
17867   /* if the content does not have a preferred size then there is
17868    * no point in computing the content box
17869    */
17870   if (!clutter_content_get_preferred_size (priv->content,
17871                                            &content_w,
17872                                            &content_h))
17873     return;
17874
17875   alloc_w = box->x2;
17876   alloc_h = box->y2;
17877
17878   switch (priv->content_gravity)
17879     {
17880     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17881       box->x2 = box->x1 + MIN (content_w, alloc_w);
17882       box->y2 = box->y1 + MIN (content_h, alloc_h);
17883       break;
17884
17885     case CLUTTER_CONTENT_GRAVITY_TOP:
17886       if (alloc_w > content_w)
17887         {
17888           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17889           box->x2 = box->x1 + content_w;
17890         }
17891       box->y2 = box->y1 + MIN (content_h, alloc_h);
17892       break;
17893
17894     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17895       if (alloc_w > content_w)
17896         {
17897           box->x1 += (alloc_w - content_w);
17898           box->x2 = box->x1 + content_w;
17899         }
17900       box->y2 = box->y1 + MIN (content_h, alloc_h);
17901       break;
17902
17903     case CLUTTER_CONTENT_GRAVITY_LEFT:
17904       box->x2 = box->x1 + MIN (content_w, alloc_w);
17905       if (alloc_h > content_h)
17906         {
17907           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17908           box->y2 = box->y1 + content_h;
17909         }
17910       break;
17911
17912     case CLUTTER_CONTENT_GRAVITY_CENTER:
17913       if (alloc_w > content_w)
17914         {
17915           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17916           box->x2 = box->x1 + content_w;
17917         }
17918       if (alloc_h > content_h)
17919         {
17920           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17921           box->y2 = box->y1 + content_h;
17922         }
17923       break;
17924
17925     case CLUTTER_CONTENT_GRAVITY_RIGHT:
17926       if (alloc_w > content_w)
17927         {
17928           box->x1 += (alloc_w - content_w);
17929           box->x2 = box->x1 + content_w;
17930         }
17931       if (alloc_h > content_h)
17932         {
17933           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17934           box->y2 = box->y1 + content_h;
17935         }
17936       break;
17937
17938     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
17939       box->x2 = box->x1 + MIN (content_w, alloc_w);
17940       if (alloc_h > content_h)
17941         {
17942           box->y1 += (alloc_h - content_h);
17943           box->y2 = box->y1 + content_h;
17944         }
17945       break;
17946
17947     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
17948       if (alloc_w > content_w)
17949         {
17950           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17951           box->x2 = box->x1 + content_w;
17952         }
17953       if (alloc_h > content_h)
17954         {
17955           box->y1 += (alloc_h - content_h);
17956           box->y2 = box->y1 + content_h;
17957         }
17958       break;
17959
17960     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
17961       if (alloc_w > content_w)
17962         {
17963           box->x1 += (alloc_w - content_w);
17964           box->x2 = box->x1 + content_w;
17965         }
17966       if (alloc_h > content_h)
17967         {
17968           box->y1 += (alloc_h - content_h);
17969           box->y2 = box->y1 + content_h;
17970         }
17971       break;
17972
17973     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
17974       g_assert_not_reached ();
17975       break;
17976
17977     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
17978       {
17979         double r_c = content_w / content_h;
17980         double r_a = alloc_w / alloc_h;
17981
17982         if (r_c >= 1.0)
17983           {
17984             if (r_a >= 1.0)
17985               {
17986                 box->x1 = 0.f;
17987                 box->x2 = alloc_w;
17988
17989                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
17990                 box->y2 = box->y1 + (alloc_w * r_c);
17991               }
17992             else
17993               {
17994                 box->y1 = 0.f;
17995                 box->y2 = alloc_h;
17996
17997                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
17998                 box->x2 = box->x1 + (alloc_h * r_c);
17999               }
18000           }
18001         else
18002           {
18003             if (r_a >= 1.0)
18004               {
18005                 box->y1 = 0.f;
18006                 box->y2 = alloc_h;
18007
18008                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18009                 box->x2 = box->x1 + (alloc_h * r_c);
18010               }
18011             else
18012               {
18013                 box->x1 = 0.f;
18014                 box->x2 = alloc_w;
18015
18016                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18017                 box->y2 = box->y1 + (alloc_w * r_c);
18018               }
18019           }
18020       }
18021       break;
18022     }
18023 }
18024
18025 /**
18026  * clutter_actor_set_content_scaling_filters:
18027  * @self: a #ClutterActor
18028  * @min_filter: the minification filter for the content
18029  * @mag_filter: the magnification filter for the content
18030  *
18031  * Sets the minification and magnification filter to be applied when
18032  * scaling the #ClutterActor:content of a #ClutterActor.
18033  *
18034  * The #ClutterActor:minification-filter will be used when reducing
18035  * the size of the content; the #ClutterActor:magnification-filter
18036  * will be used when increasing the size of the content.
18037  *
18038  * Since: 1.10
18039  */
18040 void
18041 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18042                                            ClutterScalingFilter  min_filter,
18043                                            ClutterScalingFilter  mag_filter)
18044 {
18045   ClutterActorPrivate *priv;
18046   gboolean changed;
18047   GObject *obj;
18048
18049   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18050
18051   priv = self->priv;
18052   obj = G_OBJECT (self);
18053
18054   g_object_freeze_notify (obj);
18055
18056   changed = FALSE;
18057
18058   if (priv->min_filter != min_filter)
18059     {
18060       priv->min_filter = min_filter;
18061       changed = TRUE;
18062
18063       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18064     }
18065
18066   if (priv->mag_filter != mag_filter)
18067     {
18068       priv->mag_filter = mag_filter;
18069       changed = TRUE;
18070
18071       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18072     }
18073
18074   if (changed)
18075     clutter_actor_queue_redraw (self);
18076
18077   g_object_thaw_notify (obj);
18078 }
18079
18080 /**
18081  * clutter_actor_get_content_scaling_filters:
18082  * @self: a #ClutterActor
18083  * @min_filter: (out) (allow-none): return location for the minification
18084  *   filter, or %NULL
18085  * @mag_filter: (out) (allow-none): return location for the magnification
18086  *   filter, or %NULL
18087  *
18088  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18089  *
18090  * Since: 1.10
18091  */
18092 void
18093 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18094                                            ClutterScalingFilter *min_filter,
18095                                            ClutterScalingFilter *mag_filter)
18096 {
18097   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18098
18099   if (min_filter != NULL)
18100     *min_filter = self->priv->min_filter;
18101
18102   if (mag_filter != NULL)
18103     *mag_filter = self->priv->mag_filter;
18104 }