actor: Make _clutter_actor_foreach_child() safe again
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010, 2011, 2012 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: The basic element of the scene graph 
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-painting">
119  *   <title>Painting an actor</title>
120  *   <para>There are three ways to paint an actor:</para>
121  *   <itemizedlist>
122  *     <listitem><para>set a delegate #ClutterContent as the value for the
123  *     #ClutterActor:content property of the actor;</para></listitem>
124  *     <listitem><para>subclass #ClutterActor and override the
125  *     #ClutterActorClass.paint_node() virtual function;</para></listitem>
126  *     <listitem><para>subclass #ClutterActor and override the
127  *     #ClutterActorClass.paint() virtual function.</para></listitem>
128  *   </itemizedlist>
129  *   <formalpara>
130  *     <title>Setting the Content property</title>
131  *     <para>A #ClutterContent is a delegate object that takes over the
132  *     painting operation of one, or more actors. The #ClutterContent
133  *     painting will be performed on top of the #ClutterActor:background-color
134  *     of the actor, and before calling the #ClutterActorClass.paint_node()
135  *     virtual function.</para>
136  *     <informalexample><programlisting>
137  * ClutterActor *actor = clutter_actor_new ();
138  *
139  * /&ast; set the bounding box &ast;/
140  * clutter_actor_set_position (actor, 50, 50);
141  * clutter_actor_set_size (actor, 100, 100);
142  *
143  * /&ast; set the content; the image_content variable is set elsewhere &ast;/
144  * clutter_actor_set_content (actor, image_content);
145  *     </programlisting></informalexample>
146  *   </formalpara>
147  *   <formalpara>
148  *     <title>Overriding the paint_node virtual function</title>
149  *     <para>The #ClutterActorClass.paint_node() virtual function is invoked
150  *     whenever an actor needs to be painted. The implementation of the
151  *     virtual function must only paint the contents of the actor itself,
152  *     and not the contents of its children, if the actor has any.</para>
153  *     <para>The #ClutterPaintNode passed to the virtual function is the
154  *     local root of the render tree; any node added to it will be
155  *     rendered at the correct position, as defined by the actor's
156  *     #ClutterActor:allocation.</para>
157  *     <informalexample><programlisting>
158  * static void
159  * my_actor_paint_node (ClutterActor     *actor,
160  *                      ClutterPaintNode *root)
161  * {
162  *   ClutterPaintNode *node;
163  *   ClutterActorBox box;
164  *
165  *   /&ast; where the content of the actor should be painted &ast;/
166  *   clutter_actor_get_allocation_box (actor, &box);
167  *
168  *   /&ast; the cogl_texture variable is set elsewhere &ast;/
169  *   node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170  *                                    CLUTTER_SCALING_FILTER_TRILINEAR,
171  *                                    CLUTTER_SCALING_FILTER_LINEAR);
172  *
173  *   /&ast; paint the content of the node using the allocation &ast;/
174  *   clutter_paint_node_add_rectangle (node, &box);
175  *
176  *   /&ast; add the node, and transfer ownership &ast;/
177  *   clutter_paint_node_add_child (root, node);
178  *   clutter_paint_node_unref (node);
179  * }
180  *     </programlisting></informalexample>
181  *   </formalpara>
182  *   <formalpara>
183  *     <title>Overriding the paint virtual function</title>
184  *     <para>The #ClutterActorClass.paint() virtual function is invoked
185  *     when the #ClutterActor::paint signal is emitted, and after the other
186  *     signal handlers have been invoked. Overriding the paint virtual
187  *     function gives total control to the paint sequence of the actor
188  *     itself, including the children of the actor, if any.</para>
189  *     <warning><para>It is strongly discouraged to override the
190  *     #ClutterActorClass.paint() virtual function, as well as connecting
191  *     to the #ClutterActor::paint signal. These hooks into the paint
192  *     sequence are considered legacy, and will be removed when the Clutter
193  *     API changes.</para></warning>
194  *   </formalpara>
195  * </refsect2>
196  *
197  * <refsect2 id="ClutterActor-events">
198  *   <title>Handling events on an actor</title>
199  *   <para>A #ClutterActor can receive and handle input device events, for
200  *   instance pointer events and key events, as long as its
201  *   #ClutterActor:reactive property is set to %TRUE.</para>
202  *   <para>Once an actor has been determined to be the source of an event,
203  *   Clutter will traverse the scene graph from the top-level actor towards the
204  *   event source, emitting the #ClutterActor::captured-event signal on each
205  *   ancestor until it reaches the source; this phase is also called
206  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
207  *   stopped, the graph is walked backwards, from the source actor to the
208  *   top-level, and the #ClutterActor::event signal, along with other event
209  *   signals if needed, is emitted; this phase is also called <emphasis>the
210  *   bubble phase</emphasis>. At any point of the signal emission, signal
211  *   handlers can stop the propagation through the scene graph by returning
212  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
214  * </refsect2>
215  *
216  * <refsect2 id="ClutterActor-animation">
217  *   <title>Animation</title>
218  *   <para>Animation is a core concept of modern user interfaces; Clutter
219  *   provides a complete and powerful animation framework that automatically
220  *   tweens the actor's state without requiring direct, frame by frame
221  *   manipulation from your application code.</para>
222  *   <formalpara>
223  *     <title>Implicit animations</title>
224  *     <para>The implicit animation model of Clutter assumes that all the
225  *     changes in an actor state should be gradual and asynchronous; Clutter
226  *     will automatically transition an actor's property change between the
227  *     current state and the desired one without manual intervention.</para>
228  *     <para>By default, in the 1.0 API series, the transition happens with
229  *     a duration of zero milliseconds, and the implicit animation is an
230  *     opt in feature to retain backwards compatibility. In order to enable
231  *     implicit animations, it is necessary to change the easing state of
232  *     an actor by using clutter_actor_save_easing_state():</para>
233  *     <informalexample><programlisting>
234  * /&ast; assume that the actor is currently positioned at (100, 100) &ast;/
235  * clutter_actor_save_easing_state (actor);
236  * clutter_actor_set_position (actor, 500, 500);
237  * clutter_actor_restore_easing_state (actor);
238  *     </programlisting></informalexample>
239  *     <para>The example above will trigger an implicit animation of the
240  *     actor between its current position to a new position.</para>
241  *     <para>It is possible to animate multiple properties of an actor
242  *     at the same time, and you can animate multiple actors at the same
243  *     time as well, for instance:</para>
244  *     <informalexample><programlisting>
245  * /&ast; animate the actor's opacity and depth &ast;/
246  * clutter_actor_save_easing_state (actor);
247  * clutter_actor_set_opacity (actor, 0);
248  * clutter_actor_set_depth (actor, -100);
249  * clutter_actor_restore_easing_state (actor);
250  *
251  * /&ast; animate another actor's opacity &ast;/
252  * clutter_actor_save_easing_state (another_actor);
253  * clutter_actor_set_opacity (another_actor, 255);
254  * clutter_actor_set_depth (another_actor, 100);
255  * clutter_actor_restore_easing_state (another_actor);
256  *     </programlisting></informalexample>
257  *     <para>Implicit animations use a default duration of 250 milliseconds,
258  *     and a default easing mode of %CLUTTER_EASE_OUT_CUBIC, unless you call
259  *     clutter_actor_set_easing_mode() and clutter_actor_set_easing_duration()
260  *     after changing the easing state of the actor.</para>
261  *     <para>It is important to note that if you modify the state on an
262  *     animatable property while a transition is in flight, the transition's
263  *     final value will be updated, as well as its duration and progress
264  *     mode by using the current easing state; for instance, in the following
265  *     example:</para>
266  *     <informalexample><programlisting>
267  * clutter_actor_save_easing_state (actor);
268  * clutter_actor_set_x (actor, 200);
269  * clutter_actor_restore_easing_state (actor);
270  *
271  * clutter_actor_save_easing_state (actor);
272  * clutter_actor_set_x (actor, 100);
273  * clutter_actor_restore_easing_state (actor);
274  *     </programlisting></informalexample>
275  *     <para>the first call to clutter_actor_set_x() will begin a transition
276  *     of the #ClutterActor:x property to the value of 200; the second call
277  *     to clutter_actor_set_x() will change the transition's final value to
278  *     100.</para>
279  *     <para>It is possible to retrieve the #ClutterTransition used by the
280  *     animatable properties by using clutter_actor_get_transition() and using
281  *     the property name as the transition name.</para>
282  *   </formalpara>
283  *   <formalpara>
284  *     <title>Explicit animations</title>
285  *     <para>The explicit animation model supported by Clutter requires that
286  *     you create a #ClutterTransition object, and set the initial and
287  *     final values. The transition will not start unless you add it to the
288  *     #ClutterActor.</para>
289  *     <informalexample><programlisting>
290  * ClutterTransition *transition;
291  *
292  * transition = clutter_property_transition_new ("opacity");
293  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000);
294  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
295  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
296  * clutter_transition_set_interval (transition, clutter_interval_new (G_TYPE_UINT, 255, 0));
297  *
298  * clutter_actor_add_transition (actor, "animate-opacity", transition);
299  *     </programlisting></informalexample>
300  *     <para>The example above will animate the #ClutterActor:opacity property
301  *     of an actor between fully opaque and fully transparent, and back, over
302  *     a span of 3 seconds. The animation does not begin until it is added to
303  *     the actor.</para>
304  *     <para>The explicit animation API should also be used when using custom
305  *     animatable properties for #ClutterAction, #ClutterConstraint, and
306  *     #ClutterEffect instances associated to an actor; see the section on
307  *     <ulink linkend="ClutterActor-custom-animatable-properties">custom
308  *     animatable properties below</ulink> for an example.</para>
309  *     <para>Finally, explicit animations are useful for creating animations
310  *     that run continuously, for instance:</para>
311  *     <informalexample><programlisting>
312  * /&ast; this animation will pulse the actor's opacity continuously &ast;/
313  * ClutterTransition *transition;
314  * ClutterInterval *interval;
315  *
316  * transition = clutter_property_transition_new ("opacity");
317  *
318  * /&ast; we want to animate the opacity between 0 and 255 &ast;/
319  * internal = clutter_interval_new (G_TYPE_UINT, 0, 255);
320  * clutter_transition_set_interval (transition, interval);
321  *
322  * /&ast; over a one second duration, running an infinite amount of times &ast;/
323  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
324  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
325  *
326  * /&ast; we want to fade in and out, so we need to auto-reverse the transition &ast;/
327  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
328  *
329  * /&ast; and we want to use an easing function that eases both in and out &ast;/
330  * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
331  *                                     CLUTTER_EASE_IN_OUT_CUBIC);
332  *
333  * /&ast; add the transition to the desired actor; this will
334  *  &ast; start the animation.
335  *  &ast;/
336  * clutter_actor_add_transition (actor, "opacityAnimation", transition);
337  *     </programlisting></informalexample>
338  *   </formalpara>
339  * </refsect2>
340  *
341  * <refsect2 id="ClutterActor-subclassing">
342  *   <title>Implementing an actor</title>
343  *   <para>Careful consideration should be given when deciding to implement
344  *   a #ClutterActor sub-class. It is generally recommended to implement a
345  *   sub-class of #ClutterActor only for actors that should be used as leaf
346  *   nodes of a scene graph.</para>
347  *   <para>If your actor should be painted in a custom way, you should
348  *   override the #ClutterActor::paint signal class handler. You can either
349  *   opt to chain up to the parent class implementation or decide to fully
350  *   override the default paint implementation; Clutter will set up the
351  *   transformations and clip regions prior to emitting the #ClutterActor::paint
352  *   signal.</para>
353  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
354  *   #ClutterActorClass.get_preferred_height() virtual functions it is
355  *   possible to change or provide the preferred size of an actor; similarly,
356  *   by overriding the #ClutterActorClass.allocate() virtual function it is
357  *   possible to control the layout of the children of an actor. Make sure to
358  *   always chain up to the parent implementation of the
359  *   #ClutterActorClass.allocate() virtual function.</para>
360  *   <para>In general, it is strongly encouraged to use delegation and
361  *   composition instead of direct subclassing.</para>
362  * </refsect2>
363  *
364  * <refsect2 id="ClutterActor-script">
365  *   <title>ClutterActor custom properties for #ClutterScript</title>
366  *   <para>#ClutterActor defines a custom "rotation" property which
367  *   allows a short-hand description of the rotations to be applied
368  *   to an actor.</para>
369  *   <para>The syntax of the "rotation" property is the following:</para>
370  *   <informalexample>
371  *     <programlisting>
372  * "rotation" : [
373  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
374  * ]
375  *     </programlisting>
376  *   </informalexample>
377  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
378  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
379  *   floating point value representing the rotation angle on the given axis,
380  *   in degrees.</para>
381  *   <para>The <emphasis>center</emphasis> array is optional, and if present
382  *   it must contain the center of rotation as described by two coordinates:
383  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
384  *   "z-axis".</para>
385  *   <para>#ClutterActor will also parse every positional and dimensional
386  *   property defined as a string through clutter_units_from_string(); you
387  *   should read the documentation for the #ClutterUnits parser format for
388  *   the valid units and syntax.</para>
389  * </refsect2>
390  *
391  * <refsect2 id="ClutterActor-custom-animatable-properties">
392  *   <title>Custom animatable properties</title>
393  *   <para>#ClutterActor allows accessing properties of #ClutterAction,
394  *   #ClutterEffect, and #ClutterConstraint instances associated to an actor
395  *   instance for animation purposes.</para>
396  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
397  *   property it is necessary to set the #ClutterActorMeta:name property on the
398  *   given action or constraint.</para>
399  *   <para>The property can be accessed using the following syntax:</para>
400  *   <informalexample>
401  *     <programlisting>
402  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
403  *     </programlisting>
404  *   </informalexample>
405  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
406  *   <para>The <emphasis>section</emphasis> fragment can be one between
407  *   "actions", "constraints" and "effects".</para>
408  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
409  *   action or constraint, as specified by the #ClutterActorMeta:name
410  *   property.</para>
411  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
412  *   action or constraint property to be animated.</para>
413  *   <para>The example below animates a #ClutterBindConstraint applied to an
414  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
415  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
416  *   its initial state is overlapping the actor to which is bound to.</para>
417  *   <informalexample><programlisting>
418  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
419  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
420  * clutter_actor_add_constraint (rect, constraint);
421  *
422  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
423  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
424  * clutter_actor_add_constraint (rect, constraint);
425  *
426  * clutter_actor_set_reactive (origin, TRUE);
427  *
428  * g_signal_connect (origin, "button-press-event",
429  *                   G_CALLBACK (on_button_press),
430  *                   rect);
431  *   </programlisting></informalexample>
432  *   <para>On button press, the rectangle "slides" from behind the actor to
433  *   which is bound to, using the #ClutterBindConstraint:offset property to
434  *   achieve the effect:</para>
435  *   <informalexample><programlisting>
436  * gboolean
437  * on_button_press (ClutterActor *origin,
438  *                  ClutterEvent *event,
439  *                  ClutterActor *rect)
440  * {
441  *   ClutterTransition *transition;
442  *   ClutterInterval *interval;
443  *
444  *   /&ast; the offset that we want to apply; this will make the actor
445  *    &ast; slide in from behind the origin and rest at the right of
446  *    &ast; the origin, plus a padding value.
447  *    &ast;/
448  *   float new_offset = clutter_actor_get_width (origin) + h_padding;
449  *
450  *   /&ast; the property we wish to animate; the "@constraints" section
451  *    &ast; tells Clutter to check inside the constraints associated
452  *    &ast; with the actor; the "bind-x" section is the name of the
453  *    &ast; constraint; and the "offset" is the name of the property
454  *    &ast; on the constraint.
455  *    &ast;/
456  *   const char *prop = "@constraints.bind-x.offset";
457  *
458  *   /&ast; create a new transition for the given property &ast;/
459  *   transition = clutter_property_transition_new (prop);
460  *
461  *   /&ast; set the easing mode and duration &ast;/
462  *   clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
463  *                                       CLUTTER_EASE_OUT_CUBIC);
464  *   clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
465  *
466  *   /&ast; create the interval with the initial and final values &ast;/
467  *   interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
468  *   clutter_transition_set_interval (transition, interval);
469  *
470  *   /&ast; add the transition to the actor; this causes the animation
471  *    &ast; to start. the name "offsetAnimation" can be used to retrieve
472  *    &ast; the transition later.
473  *    &ast;/
474  *   clutter_actor_add_transition (rect, "offsetAnimation", transition);
475  *
476  *   /&ast; we handled the event &ast;/
477  *   return CLUTTER_EVENT_STOP;
478  * }
479  *   </programlisting></informalexample>
480  * </refsect2>
481  */
482
483 /**
484  * CLUTTER_ACTOR_IS_MAPPED:
485  * @a: a #ClutterActor
486  *
487  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
488  *
489  * The mapped state is set when the actor is visible and all its parents up
490  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
491  *
492  * This check can be used to see if an actor is going to be painted, as only
493  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
494  *
495  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
496  * not be checked directly; instead, the recommended usage is to connect a
497  * handler on the #GObject::notify signal for the #ClutterActor:mapped
498  * property of #ClutterActor, and check the presence of
499  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
500  *
501  * It is also important to note that Clutter may delay the changes of
502  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
503  * limitations, or during the reparenting of an actor, to optimize
504  * unnecessary (and potentially expensive) state changes.
505  *
506  * Since: 0.2
507  */
508
509 /**
510  * CLUTTER_ACTOR_IS_REALIZED:
511  * @a: a #ClutterActor
512  *
513  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
514  *
515  * The realized state has an actor-dependant interpretation. If an
516  * actor wants to delay allocating resources until it is attached to a
517  * stage, it may use the realize state to do so. However it is
518  * perfectly acceptable for an actor to allocate Cogl resources before
519  * being realized because there is only one drawing context used by Clutter
520  * so any resources will work on any stage.  If an actor is mapped it
521  * must also be realized, but an actor can be realized and unmapped
522  * (this is so hiding an actor temporarily doesn't do an expensive
523  * unrealize/realize).
524  *
525  * To be realized an actor must be inside a stage, and all its parents
526  * must be realized.
527  *
528  * Since: 0.2
529  */
530
531 /**
532  * CLUTTER_ACTOR_IS_VISIBLE:
533  * @a: a #ClutterActor
534  *
535  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
536  * Equivalent to the ClutterActor::visible object property.
537  *
538  * Note that an actor is only painted onscreen if it's mapped, which
539  * means it's visible, and all its parents are visible, and one of the
540  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
541  *
542  * Since: 0.2
543  */
544
545 /**
546  * CLUTTER_ACTOR_IS_REACTIVE:
547  * @a: a #ClutterActor
548  *
549  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
550  *
551  * Only reactive actors will receive event-related signals.
552  *
553  * Since: 0.6
554  */
555
556 #ifdef HAVE_CONFIG_H
557 #include "config.h"
558 #endif
559
560 #include <math.h>
561
562 #include <gobject/gvaluecollector.h>
563
564 #include <cogl/cogl.h>
565
566 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
567 #define CLUTTER_ENABLE_EXPERIMENTAL_API
568
569 #include "clutter-actor-private.h"
570
571 #include "clutter-action.h"
572 #include "clutter-actor-meta-private.h"
573 #include "clutter-animatable.h"
574 #include "clutter-color-static.h"
575 #include "clutter-color.h"
576 #include "clutter-constraint.h"
577 #include "clutter-container.h"
578 #include "clutter-content-private.h"
579 #include "clutter-debug.h"
580 #include "clutter-effect-private.h"
581 #include "clutter-enum-types.h"
582 #include "clutter-fixed-layout.h"
583 #include "clutter-flatten-effect.h"
584 #include "clutter-interval.h"
585 #include "clutter-main.h"
586 #include "clutter-marshal.h"
587 #include "clutter-paint-nodes.h"
588 #include "clutter-paint-node-private.h"
589 #include "clutter-paint-volume-private.h"
590 #include "clutter-private.h"
591 #include "clutter-profile.h"
592 #include "clutter-property-transition.h"
593 #include "clutter-scriptable.h"
594 #include "clutter-script-private.h"
595 #include "clutter-stage-private.h"
596 #include "clutter-timeline.h"
597 #include "clutter-transition.h"
598 #include "clutter-units.h"
599
600 #include "deprecated/clutter-actor.h"
601 #include "deprecated/clutter-behaviour.h"
602 #include "deprecated/clutter-container.h"
603
604 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
605 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
606
607 /* Internal enum used to control mapped state update.  This is a hint
608  * which indicates when to do something other than just enforce
609  * invariants.
610  */
611 typedef enum {
612   MAP_STATE_CHECK,           /* just enforce invariants. */
613   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
614                               * used when about to unparent.
615                               */
616   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
617                               * used to set mapped on toplevels.
618                               */
619   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
620                               * used just before unmapping parent.
621                               */
622 } MapStateChange;
623
624 /* 3 entries should be a good compromise, few layout managers
625  * will ask for 3 different preferred size in each allocation cycle */
626 #define N_CACHED_SIZE_REQUESTS 3
627
628 struct _ClutterActorPrivate
629 {
630   /* request mode */
631   ClutterRequestMode request_mode;
632
633   /* our cached size requests for different width / height */
634   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
635   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
636
637   /* An age of 0 means the entry is not set */
638   guint cached_height_age;
639   guint cached_width_age;
640
641   /* the bounding box of the actor, relative to the parent's
642    * allocation
643    */
644   ClutterActorBox allocation;
645   ClutterAllocationFlags allocation_flags;
646
647   /* clip, in actor coordinates */
648   cairo_rectangle_t clip;
649
650   /* the cached transformation matrix; see apply_transform() */
651   CoglMatrix transform;
652
653   guint8 opacity;
654   gint opacity_override;
655
656   ClutterOffscreenRedirect offscreen_redirect;
657
658   /* This is an internal effect used to implement the
659      offscreen-redirect property */
660   ClutterEffect *flatten_effect;
661
662   /* scene graph */
663   ClutterActor *parent;
664   ClutterActor *prev_sibling;
665   ClutterActor *next_sibling;
666   ClutterActor *first_child;
667   ClutterActor *last_child;
668
669   gint n_children;
670
671   /* tracks whenever the children of an actor are changed; the
672    * age is incremented by 1 whenever an actor is added or
673    * removed. the age is not incremented when the first or the
674    * last child pointers are changed, or when grandchildren of
675    * an actor are changed.
676    */
677   gint age;
678
679   gchar *name; /* a non-unique name, used for debugging */
680   guint32 id; /* unique id, used for backward compatibility */
681
682   gint32 pick_id; /* per-stage unique id, used for picking */
683
684   /* a back-pointer to the Pango context that we can use
685    * to create pre-configured PangoLayout
686    */
687   PangoContext *pango_context;
688
689   /* the text direction configured for this child - either by
690    * application code, or by the actor's parent
691    */
692   ClutterTextDirection text_direction;
693
694   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
695   gint internal_child;
696
697   /* meta classes */
698   ClutterMetaGroup *actions;
699   ClutterMetaGroup *constraints;
700   ClutterMetaGroup *effects;
701
702   /* delegate object used to allocate the children of this actor */
703   ClutterLayoutManager *layout_manager;
704
705   /* delegate object used to paint the contents of this actor */
706   ClutterContent *content;
707
708   ClutterActorBox content_box;
709   ClutterContentGravity content_gravity;
710   ClutterScalingFilter min_filter;
711   ClutterScalingFilter mag_filter;
712
713   /* used when painting, to update the paint volume */
714   ClutterEffect *current_effect;
715
716   /* This is used to store an effect which needs to be redrawn. A
717      redraw can be queued to start from a particular effect. This is
718      used by parametrised effects that can cache an image of the
719      actor. If a parameter of the effect changes then it only needs to
720      redraw the cached image, not the actual actor. The pointer is
721      only valid if is_dirty == TRUE. If the pointer is NULL then the
722      whole actor is dirty. */
723   ClutterEffect *effect_to_redraw;
724
725   /* This is used when painting effects to implement the
726      clutter_actor_continue_paint() function. It points to the node in
727      the list of effects that is next in the chain */
728   const GList *next_effect_to_paint;
729
730   ClutterPaintVolume paint_volume;
731
732   /* NB: This volume isn't relative to this actor, it is in eye
733    * coordinates so that it can remain valid after the actor changes.
734    */
735   ClutterPaintVolume last_paint_volume;
736
737   ClutterStageQueueRedrawEntry *queue_redraw_entry;
738
739   ClutterColor bg_color;
740
741   /* bitfields */
742
743   /* fixed position and sizes */
744   guint position_set                : 1;
745   guint min_width_set               : 1;
746   guint min_height_set              : 1;
747   guint natural_width_set           : 1;
748   guint natural_height_set          : 1;
749   /* cached request is invalid (implies allocation is too) */
750   guint needs_width_request         : 1;
751   /* cached request is invalid (implies allocation is too) */
752   guint needs_height_request        : 1;
753   /* cached allocation is invalid (request has changed, probably) */
754   guint needs_allocation            : 1;
755   guint show_on_set_parent          : 1;
756   guint has_clip                    : 1;
757   guint clip_to_allocation          : 1;
758   guint enable_model_view_transform : 1;
759   guint enable_paint_unmapped       : 1;
760   guint has_pointer                 : 1;
761   guint propagated_one_redraw       : 1;
762   guint paint_volume_valid          : 1;
763   guint last_paint_volume_valid     : 1;
764   guint in_clone_paint              : 1;
765   guint transform_valid             : 1;
766   /* This is TRUE if anything has queued a redraw since we were last
767      painted. In this case effect_to_redraw will point to an effect
768      the redraw was queued from or it will be NULL if the redraw was
769      queued without an effect. */
770   guint is_dirty                    : 1;
771   guint bg_color_set                : 1;
772   guint content_box_valid           : 1;
773 };
774
775 enum
776 {
777   PROP_0,
778
779   PROP_NAME,
780
781   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
782    * when set they force a size request, when gotten they
783    * get the allocation if the allocation is valid, and the
784    * request otherwise
785    */
786   PROP_X,
787   PROP_Y,
788   PROP_WIDTH,
789   PROP_HEIGHT,
790
791   /* Then the rest of these size-related properties are the "actual"
792    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
793    */
794   PROP_FIXED_X,
795   PROP_FIXED_Y,
796
797   PROP_FIXED_POSITION_SET,
798
799   PROP_MIN_WIDTH,
800   PROP_MIN_WIDTH_SET,
801
802   PROP_MIN_HEIGHT,
803   PROP_MIN_HEIGHT_SET,
804
805   PROP_NATURAL_WIDTH,
806   PROP_NATURAL_WIDTH_SET,
807
808   PROP_NATURAL_HEIGHT,
809   PROP_NATURAL_HEIGHT_SET,
810
811   PROP_REQUEST_MODE,
812
813   /* Allocation properties are read-only */
814   PROP_ALLOCATION,
815
816   PROP_DEPTH,
817
818   PROP_CLIP,
819   PROP_HAS_CLIP,
820   PROP_CLIP_TO_ALLOCATION,
821
822   PROP_OPACITY,
823
824   PROP_OFFSCREEN_REDIRECT,
825
826   PROP_VISIBLE,
827   PROP_MAPPED,
828   PROP_REALIZED,
829   PROP_REACTIVE,
830
831   PROP_SCALE_X,
832   PROP_SCALE_Y,
833   PROP_SCALE_CENTER_X,
834   PROP_SCALE_CENTER_Y,
835   PROP_SCALE_GRAVITY,
836
837   PROP_ROTATION_ANGLE_X,
838   PROP_ROTATION_ANGLE_Y,
839   PROP_ROTATION_ANGLE_Z,
840   PROP_ROTATION_CENTER_X,
841   PROP_ROTATION_CENTER_Y,
842   PROP_ROTATION_CENTER_Z,
843   /* This property only makes sense for the z rotation because the
844      others would depend on the actor having a size along the
845      z-axis */
846   PROP_ROTATION_CENTER_Z_GRAVITY,
847
848   PROP_ANCHOR_X,
849   PROP_ANCHOR_Y,
850   PROP_ANCHOR_GRAVITY,
851
852   PROP_SHOW_ON_SET_PARENT,
853
854   PROP_TEXT_DIRECTION,
855   PROP_HAS_POINTER,
856
857   PROP_ACTIONS,
858   PROP_CONSTRAINTS,
859   PROP_EFFECT,
860
861   PROP_LAYOUT_MANAGER,
862
863   PROP_X_ALIGN,
864   PROP_Y_ALIGN,
865   PROP_MARGIN_TOP,
866   PROP_MARGIN_BOTTOM,
867   PROP_MARGIN_LEFT,
868   PROP_MARGIN_RIGHT,
869
870   PROP_BACKGROUND_COLOR,
871   PROP_BACKGROUND_COLOR_SET,
872
873   PROP_FIRST_CHILD,
874   PROP_LAST_CHILD,
875
876   PROP_CONTENT,
877   PROP_CONTENT_GRAVITY,
878   PROP_CONTENT_BOX,
879   PROP_MINIFICATION_FILTER,
880   PROP_MAGNIFICATION_FILTER,
881
882   PROP_LAST
883 };
884
885 static GParamSpec *obj_props[PROP_LAST];
886
887 enum
888 {
889   SHOW,
890   HIDE,
891   DESTROY,
892   PARENT_SET,
893   KEY_FOCUS_IN,
894   KEY_FOCUS_OUT,
895   PAINT,
896   PICK,
897   REALIZE,
898   UNREALIZE,
899   QUEUE_REDRAW,
900   QUEUE_RELAYOUT,
901   EVENT,
902   CAPTURED_EVENT,
903   BUTTON_PRESS_EVENT,
904   BUTTON_RELEASE_EVENT,
905   SCROLL_EVENT,
906   KEY_PRESS_EVENT,
907   KEY_RELEASE_EVENT,
908   MOTION_EVENT,
909   ENTER_EVENT,
910   LEAVE_EVENT,
911   ALLOCATION_CHANGED,
912   TRANSITIONS_COMPLETED,
913
914   LAST_SIGNAL
915 };
916
917 static guint actor_signals[LAST_SIGNAL] = { 0, };
918
919 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
920 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
921 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
922 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
923
924 /* These setters are all static for now, maybe they should be in the
925  * public API, but they are perhaps obscure enough to leave only as
926  * properties
927  */
928 static void clutter_actor_set_min_width          (ClutterActor *self,
929                                                   gfloat        min_width);
930 static void clutter_actor_set_min_height         (ClutterActor *self,
931                                                   gfloat        min_height);
932 static void clutter_actor_set_natural_width      (ClutterActor *self,
933                                                   gfloat        natural_width);
934 static void clutter_actor_set_natural_height     (ClutterActor *self,
935                                                   gfloat        natural_height);
936 static void clutter_actor_set_min_width_set      (ClutterActor *self,
937                                                   gboolean      use_min_width);
938 static void clutter_actor_set_min_height_set     (ClutterActor *self,
939                                                   gboolean      use_min_height);
940 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
941                                                   gboolean  use_natural_width);
942 static void clutter_actor_set_natural_height_set (ClutterActor *self,
943                                                   gboolean  use_natural_height);
944 static void clutter_actor_update_map_state       (ClutterActor  *self,
945                                                   MapStateChange change);
946 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
947
948 /* Helper routines for managing anchor coords */
949 static void clutter_anchor_coord_get_units (ClutterActor      *self,
950                                             const AnchorCoord *coord,
951                                             gfloat            *x,
952                                             gfloat            *y,
953                                             gfloat            *z);
954 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
955                                             gfloat             x,
956                                             gfloat             y,
957                                             gfloat             z);
958
959 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
960 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
961                                                         ClutterGravity     gravity);
962
963 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
964
965 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
966
967 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
968                                                                ClutterActor *ancestor,
969                                                                CoglMatrix *matrix);
970
971 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
972
973 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
974
975 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
976                                                                 const ClutterColor *color);
977
978 static void on_layout_manager_changed (ClutterLayoutManager *manager,
979                                        ClutterActor         *self);
980
981 /* Helper macro which translates by the anchor coord, applies the
982    given transformation and then translates back */
983 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
984   gfloat _tx, _ty, _tz;                                                \
985   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
986   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
987   { _transform; }                                                      \
988   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
989
990 static GQuark quark_shader_data = 0;
991 static GQuark quark_actor_layout_info = 0;
992 static GQuark quark_actor_transform_info = 0;
993 static GQuark quark_actor_animation_info = 0;
994
995 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
996                          clutter_actor,
997                          G_TYPE_INITIALLY_UNOWNED,
998                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
999                                                 clutter_container_iface_init)
1000                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1001                                                 clutter_scriptable_iface_init)
1002                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1003                                                 clutter_animatable_iface_init)
1004                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1005                                                 atk_implementor_iface_init));
1006
1007 /*< private >
1008  * clutter_actor_get_debug_name:
1009  * @actor: a #ClutterActor
1010  *
1011  * Retrieves a printable name of @actor for debugging messages
1012  *
1013  * Return value: a string with a printable name
1014  */
1015 const gchar *
1016 _clutter_actor_get_debug_name (ClutterActor *actor)
1017 {
1018   return actor->priv->name != NULL ? actor->priv->name
1019                                    : G_OBJECT_TYPE_NAME (actor);
1020 }
1021
1022 #ifdef CLUTTER_ENABLE_DEBUG
1023 /* XXX - this is for debugging only, remove once working (or leave
1024  * in only in some debug mode). Should leave it for a little while
1025  * until we're confident in the new map/realize/visible handling.
1026  */
1027 static inline void
1028 clutter_actor_verify_map_state (ClutterActor *self)
1029 {
1030   ClutterActorPrivate *priv = self->priv;
1031
1032   if (CLUTTER_ACTOR_IS_REALIZED (self))
1033     {
1034       /* all bets are off during reparent when we're potentially realized,
1035        * but should not be according to invariants
1036        */
1037       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1038         {
1039           if (priv->parent == NULL)
1040             {
1041               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1042                 {
1043                 }
1044               else
1045                 g_warning ("Realized non-toplevel actor '%s' should "
1046                            "have a parent",
1047                            _clutter_actor_get_debug_name (self));
1048             }
1049           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1050             {
1051               g_warning ("Realized actor %s has an unrealized parent %s",
1052                          _clutter_actor_get_debug_name (self),
1053                          _clutter_actor_get_debug_name (priv->parent));
1054             }
1055         }
1056     }
1057
1058   if (CLUTTER_ACTOR_IS_MAPPED (self))
1059     {
1060       if (!CLUTTER_ACTOR_IS_REALIZED (self))
1061         g_warning ("Actor '%s' is mapped but not realized",
1062                    _clutter_actor_get_debug_name (self));
1063
1064       /* remaining bets are off during reparent when we're potentially
1065        * mapped, but should not be according to invariants
1066        */
1067       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1068         {
1069           if (priv->parent == NULL)
1070             {
1071               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1072                 {
1073                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1074                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1075                     {
1076                       g_warning ("Toplevel actor '%s' is mapped "
1077                                  "but not visible",
1078                                  _clutter_actor_get_debug_name (self));
1079                     }
1080                 }
1081               else
1082                 {
1083                   g_warning ("Mapped actor '%s' should have a parent",
1084                              _clutter_actor_get_debug_name (self));
1085                 }
1086             }
1087           else
1088             {
1089               ClutterActor *iter = self;
1090
1091               /* check for the enable_paint_unmapped flag on the actor
1092                * and parents; if the flag is enabled at any point of this
1093                * branch of the scene graph then all the later checks
1094                * become pointless
1095                */
1096               while (iter != NULL)
1097                 {
1098                   if (iter->priv->enable_paint_unmapped)
1099                     return;
1100
1101                   iter = iter->priv->parent;
1102                 }
1103
1104               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1105                 {
1106                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1107                              "is not visible",
1108                              _clutter_actor_get_debug_name (self),
1109                              _clutter_actor_get_debug_name (priv->parent));
1110                 }
1111
1112               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1113                 {
1114                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1115                              "is not realized",
1116                              _clutter_actor_get_debug_name (self),
1117                              _clutter_actor_get_debug_name (priv->parent));
1118                 }
1119
1120               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1121                 {
1122                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1123                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1124                                "parent '%s' is not mapped",
1125                                _clutter_actor_get_debug_name (self),
1126                                _clutter_actor_get_debug_name (priv->parent));
1127                 }
1128             }
1129         }
1130     }
1131 }
1132
1133 #endif /* CLUTTER_ENABLE_DEBUG */
1134
1135 static void
1136 clutter_actor_set_mapped (ClutterActor *self,
1137                           gboolean      mapped)
1138 {
1139   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1140     return;
1141
1142   if (mapped)
1143     {
1144       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1145       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1146     }
1147   else
1148     {
1149       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1150       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1151     }
1152 }
1153
1154 /* this function updates the mapped and realized states according to
1155  * invariants, in the appropriate order.
1156  */
1157 static void
1158 clutter_actor_update_map_state (ClutterActor  *self,
1159                                 MapStateChange change)
1160 {
1161   gboolean was_mapped;
1162
1163   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1164
1165   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1166     {
1167       /* the mapped flag on top-level actors must be set by the
1168        * per-backend implementation because it might be asynchronous.
1169        *
1170        * That is, the MAPPED flag on toplevels currently tracks the X
1171        * server mapped-ness of the window, while the expected behavior
1172        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1173        * This creates some weird complexity by breaking the invariant
1174        * that if we're visible and all ancestors shown then we are
1175        * also mapped - instead, we are mapped if all ancestors
1176        * _possibly excepting_ the stage are mapped. The stage
1177        * will map/unmap for example when it is minimized or
1178        * moved to another workspace.
1179        *
1180        * So, the only invariant on the stage is that if visible it
1181        * should be realized, and that it has to be visible to be
1182        * mapped.
1183        */
1184       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1185         clutter_actor_realize (self);
1186
1187       switch (change)
1188         {
1189         case MAP_STATE_CHECK:
1190           break;
1191
1192         case MAP_STATE_MAKE_MAPPED:
1193           g_assert (!was_mapped);
1194           clutter_actor_set_mapped (self, TRUE);
1195           break;
1196
1197         case MAP_STATE_MAKE_UNMAPPED:
1198           g_assert (was_mapped);
1199           clutter_actor_set_mapped (self, FALSE);
1200           break;
1201
1202         case MAP_STATE_MAKE_UNREALIZED:
1203           /* we only use MAKE_UNREALIZED in unparent,
1204            * and unparenting a stage isn't possible.
1205            * If someone wants to just unrealize a stage
1206            * then clutter_actor_unrealize() doesn't
1207            * go through this codepath.
1208            */
1209           g_warning ("Trying to force unrealize stage is not allowed");
1210           break;
1211         }
1212
1213       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1214           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1215           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1216         {
1217           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1218                      "it is somehow still mapped",
1219                      _clutter_actor_get_debug_name (self));
1220         }
1221     }
1222   else
1223     {
1224       ClutterActorPrivate *priv = self->priv;
1225       ClutterActor *parent = priv->parent;
1226       gboolean should_be_mapped;
1227       gboolean may_be_realized;
1228       gboolean must_be_realized;
1229
1230       should_be_mapped = FALSE;
1231       may_be_realized = TRUE;
1232       must_be_realized = FALSE;
1233
1234       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1235         {
1236           may_be_realized = FALSE;
1237         }
1238       else
1239         {
1240           /* Maintain invariant that if parent is mapped, and we are
1241            * visible, then we are mapped ...  unless parent is a
1242            * stage, in which case we map regardless of parent's map
1243            * state but do require stage to be visible and realized.
1244            *
1245            * If parent is realized, that does not force us to be
1246            * realized; but if parent is unrealized, that does force
1247            * us to be unrealized.
1248            *
1249            * The reason we don't force children to realize with
1250            * parents is _clutter_actor_rerealize(); if we require that
1251            * a realized parent means children are realized, then to
1252            * unrealize an actor we would have to unrealize its
1253            * parents, which would end up meaning unrealizing and
1254            * hiding the entire stage. So we allow unrealizing a
1255            * child (as long as that child is not mapped) while that
1256            * child still has a realized parent.
1257            *
1258            * Also, if we unrealize from leaf nodes to root, and
1259            * realize from root to leaf, the invariants are never
1260            * violated if we allow children to be unrealized
1261            * while parents are realized.
1262            *
1263            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1264            * to force us to unmap, even though parent is still
1265            * mapped. This is because we're unmapping from leaf nodes
1266            * up to root nodes.
1267            */
1268           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1269               change != MAP_STATE_MAKE_UNMAPPED)
1270             {
1271               gboolean parent_is_visible_realized_toplevel;
1272
1273               parent_is_visible_realized_toplevel =
1274                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1275                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1276                  CLUTTER_ACTOR_IS_REALIZED (parent));
1277
1278               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1279                   parent_is_visible_realized_toplevel)
1280                 {
1281                   must_be_realized = TRUE;
1282                   should_be_mapped = TRUE;
1283                 }
1284             }
1285
1286           /* if the actor has been set to be painted even if unmapped
1287            * then we should map it and check for realization as well;
1288            * this is an override for the branch of the scene graph
1289            * which begins with this node
1290            */
1291           if (priv->enable_paint_unmapped)
1292             {
1293               if (priv->parent == NULL)
1294                 g_warning ("Attempting to map an unparented actor '%s'",
1295                            _clutter_actor_get_debug_name (self));
1296
1297               should_be_mapped = TRUE;
1298               must_be_realized = TRUE;
1299             }
1300
1301           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1302             may_be_realized = FALSE;
1303         }
1304
1305       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1306         {
1307           if (parent == NULL)
1308             g_warning ("Attempting to map a child that does not "
1309                        "meet the necessary invariants: the actor '%s' "
1310                        "has no parent",
1311                        _clutter_actor_get_debug_name (self));
1312           else
1313             g_warning ("Attempting to map a child that does not "
1314                        "meet the necessary invariants: the actor '%s' "
1315                        "is parented to an unmapped actor '%s'",
1316                        _clutter_actor_get_debug_name (self),
1317                        _clutter_actor_get_debug_name (priv->parent));
1318         }
1319
1320       /* If in reparent, we temporarily suspend unmap and unrealize.
1321        *
1322        * We want to go in the order "realize, map" and "unmap, unrealize"
1323        */
1324
1325       /* Unmap */
1326       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1327         clutter_actor_set_mapped (self, FALSE);
1328
1329       /* Realize */
1330       if (must_be_realized)
1331         clutter_actor_realize (self);
1332
1333       /* if we must be realized then we may be, presumably */
1334       g_assert (!(must_be_realized && !may_be_realized));
1335
1336       /* Unrealize */
1337       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1338         clutter_actor_unrealize_not_hiding (self);
1339
1340       /* Map */
1341       if (should_be_mapped)
1342         {
1343           if (!must_be_realized)
1344             g_warning ("Somehow we think actor '%s' should be mapped but "
1345                        "not realized, which isn't allowed",
1346                        _clutter_actor_get_debug_name (self));
1347
1348           /* realization is allowed to fail (though I don't know what
1349            * an app is supposed to do about that - shouldn't it just
1350            * be a g_error? anyway, we have to avoid mapping if this
1351            * happens)
1352            */
1353           if (CLUTTER_ACTOR_IS_REALIZED (self))
1354             clutter_actor_set_mapped (self, TRUE);
1355         }
1356     }
1357
1358 #ifdef CLUTTER_ENABLE_DEBUG
1359   /* check all invariants were kept */
1360   clutter_actor_verify_map_state (self);
1361 #endif
1362 }
1363
1364 static void
1365 clutter_actor_real_map (ClutterActor *self)
1366 {
1367   ClutterActorPrivate *priv = self->priv;
1368   ClutterActor *stage, *iter;
1369
1370   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1371
1372   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1373                 _clutter_actor_get_debug_name (self));
1374
1375   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1376
1377   stage = _clutter_actor_get_stage_internal (self);
1378   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1379
1380   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1381                 priv->pick_id,
1382                 _clutter_actor_get_debug_name (self));
1383
1384   /* notify on parent mapped before potentially mapping
1385    * children, so apps see a top-down notification.
1386    */
1387   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1388
1389   for (iter = self->priv->first_child;
1390        iter != NULL;
1391        iter = iter->priv->next_sibling)
1392     {
1393       clutter_actor_map (iter);
1394     }
1395 }
1396
1397 /**
1398  * clutter_actor_map:
1399  * @self: A #ClutterActor
1400  *
1401  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1402  * and realizes its children if they are visible. Does nothing if the
1403  * actor is not visible.
1404  *
1405  * Calling this function is strongly disencouraged: the default
1406  * implementation of #ClutterActorClass.map() will map all the children
1407  * of an actor when mapping its parent.
1408  *
1409  * When overriding map, it is mandatory to chain up to the parent
1410  * implementation.
1411  *
1412  * Since: 1.0
1413  */
1414 void
1415 clutter_actor_map (ClutterActor *self)
1416 {
1417   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1418
1419   if (CLUTTER_ACTOR_IS_MAPPED (self))
1420     return;
1421
1422   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1423     return;
1424
1425   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1426 }
1427
1428 static void
1429 clutter_actor_real_unmap (ClutterActor *self)
1430 {
1431   ClutterActorPrivate *priv = self->priv;
1432   ClutterActor *iter;
1433
1434   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1435
1436   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1437                 _clutter_actor_get_debug_name (self));
1438
1439   for (iter = self->priv->first_child;
1440        iter != NULL;
1441        iter = iter->priv->next_sibling)
1442     {
1443       clutter_actor_unmap (iter);
1444     }
1445
1446   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1447
1448   /* clear the contents of the last paint volume, so that hiding + moving +
1449    * showing will not result in the wrong area being repainted
1450    */
1451   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1452   priv->last_paint_volume_valid = TRUE;
1453
1454   /* notify on parent mapped after potentially unmapping
1455    * children, so apps see a bottom-up notification.
1456    */
1457   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1458
1459   /* relinquish keyboard focus if we were unmapped while owning it */
1460   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1461     {
1462       ClutterStage *stage;
1463
1464       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1465
1466       if (stage != NULL)
1467         _clutter_stage_release_pick_id (stage, priv->pick_id);
1468
1469       priv->pick_id = -1;
1470
1471       if (stage != NULL &&
1472           clutter_stage_get_key_focus (stage) == self)
1473         {
1474           clutter_stage_set_key_focus (stage, NULL);
1475         }
1476     }
1477 }
1478
1479 /**
1480  * clutter_actor_unmap:
1481  * @self: A #ClutterActor
1482  *
1483  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1484  * unmaps its children if they were mapped.
1485  *
1486  * Calling this function is not encouraged: the default #ClutterActor
1487  * implementation of #ClutterActorClass.unmap() will also unmap any
1488  * eventual children by default when their parent is unmapped.
1489  *
1490  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1491  * chain up to the parent implementation.
1492  *
1493  * <note>It is important to note that the implementation of the
1494  * #ClutterActorClass.unmap() virtual function may be called after
1495  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1496  * implementation, but it is guaranteed to be called before the
1497  * #GObjectClass.finalize() implementation.</note>
1498  *
1499  * Since: 1.0
1500  */
1501 void
1502 clutter_actor_unmap (ClutterActor *self)
1503 {
1504   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1505
1506   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1507     return;
1508
1509   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1510 }
1511
1512 static void
1513 clutter_actor_real_show (ClutterActor *self)
1514 {
1515   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1516     {
1517       ClutterActorPrivate *priv = self->priv;
1518
1519       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1520
1521       /* we notify on the "visible" flag in the clutter_actor_show()
1522        * wrapper so the entire show signal emission completes first
1523        * (?)
1524        */
1525       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1526
1527       /* we queue a relayout unless the actor is inside a
1528        * container that explicitly told us not to
1529        */
1530       if (priv->parent != NULL &&
1531           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1532         {
1533           /* While an actor is hidden the parent may not have
1534            * allocated/requested so we need to start from scratch
1535            * and avoid the short-circuiting in
1536            * clutter_actor_queue_relayout().
1537            */
1538           priv->needs_width_request  = FALSE;
1539           priv->needs_height_request = FALSE;
1540           priv->needs_allocation     = FALSE;
1541           clutter_actor_queue_relayout (self);
1542         }
1543     }
1544 }
1545
1546 static inline void
1547 set_show_on_set_parent (ClutterActor *self,
1548                         gboolean      set_show)
1549 {
1550   ClutterActorPrivate *priv = self->priv;
1551
1552   set_show = !!set_show;
1553
1554   if (priv->show_on_set_parent == set_show)
1555     return;
1556
1557   if (priv->parent == NULL)
1558     {
1559       priv->show_on_set_parent = set_show;
1560       g_object_notify_by_pspec (G_OBJECT (self),
1561                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1562     }
1563 }
1564
1565 /**
1566  * clutter_actor_show:
1567  * @self: A #ClutterActor
1568  *
1569  * Flags an actor to be displayed. An actor that isn't shown will not
1570  * be rendered on the stage.
1571  *
1572  * Actors are visible by default.
1573  *
1574  * If this function is called on an actor without a parent, the
1575  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1576  * effect.
1577  */
1578 void
1579 clutter_actor_show (ClutterActor *self)
1580 {
1581   ClutterActorPrivate *priv;
1582
1583   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1584
1585   /* simple optimization */
1586   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1587     {
1588       /* we still need to set the :show-on-set-parent property, in
1589        * case show() is called on an unparented actor
1590        */
1591       set_show_on_set_parent (self, TRUE);
1592       return;
1593     }
1594
1595 #ifdef CLUTTER_ENABLE_DEBUG
1596   clutter_actor_verify_map_state (self);
1597 #endif
1598
1599   priv = self->priv;
1600
1601   g_object_freeze_notify (G_OBJECT (self));
1602
1603   set_show_on_set_parent (self, TRUE);
1604
1605   g_signal_emit (self, actor_signals[SHOW], 0);
1606   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1607
1608   if (priv->parent != NULL)
1609     clutter_actor_queue_redraw (priv->parent);
1610
1611   g_object_thaw_notify (G_OBJECT (self));
1612 }
1613
1614 /**
1615  * clutter_actor_show_all:
1616  * @self: a #ClutterActor
1617  *
1618  * Calls clutter_actor_show() on all children of an actor (if any).
1619  *
1620  * Since: 0.2
1621  *
1622  * Deprecated: 1.10: Actors are visible by default
1623  */
1624 void
1625 clutter_actor_show_all (ClutterActor *self)
1626 {
1627   ClutterActorClass *klass;
1628
1629   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1630
1631   klass = CLUTTER_ACTOR_GET_CLASS (self);
1632   if (klass->show_all)
1633     klass->show_all (self);
1634 }
1635
1636 static void
1637 clutter_actor_real_hide (ClutterActor *self)
1638 {
1639   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1640     {
1641       ClutterActorPrivate *priv = self->priv;
1642
1643       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1644
1645       /* we notify on the "visible" flag in the clutter_actor_hide()
1646        * wrapper so the entire hide signal emission completes first
1647        * (?)
1648        */
1649       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1650
1651       /* we queue a relayout unless the actor is inside a
1652        * container that explicitly told us not to
1653        */
1654       if (priv->parent != NULL &&
1655           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1656         clutter_actor_queue_relayout (priv->parent);
1657     }
1658 }
1659
1660 /**
1661  * clutter_actor_hide:
1662  * @self: A #ClutterActor
1663  *
1664  * Flags an actor to be hidden. A hidden actor will not be
1665  * rendered on the stage.
1666  *
1667  * Actors are visible by default.
1668  *
1669  * If this function is called on an actor without a parent, the
1670  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1671  * as a side-effect.
1672  */
1673 void
1674 clutter_actor_hide (ClutterActor *self)
1675 {
1676   ClutterActorPrivate *priv;
1677
1678   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1679
1680   /* simple optimization */
1681   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1682     {
1683       /* we still need to set the :show-on-set-parent property, in
1684        * case hide() is called on an unparented actor
1685        */
1686       set_show_on_set_parent (self, FALSE);
1687       return;
1688     }
1689
1690 #ifdef CLUTTER_ENABLE_DEBUG
1691   clutter_actor_verify_map_state (self);
1692 #endif
1693
1694   priv = self->priv;
1695
1696   g_object_freeze_notify (G_OBJECT (self));
1697
1698   set_show_on_set_parent (self, FALSE);
1699
1700   g_signal_emit (self, actor_signals[HIDE], 0);
1701   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1702
1703   if (priv->parent != NULL)
1704     clutter_actor_queue_redraw (priv->parent);
1705
1706   g_object_thaw_notify (G_OBJECT (self));
1707 }
1708
1709 /**
1710  * clutter_actor_hide_all:
1711  * @self: a #ClutterActor
1712  *
1713  * Calls clutter_actor_hide() on all child actors (if any).
1714  *
1715  * Since: 0.2
1716  *
1717  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1718  *   prevent its children from being painted as well.
1719  */
1720 void
1721 clutter_actor_hide_all (ClutterActor *self)
1722 {
1723   ClutterActorClass *klass;
1724
1725   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1726
1727   klass = CLUTTER_ACTOR_GET_CLASS (self);
1728   if (klass->hide_all)
1729     klass->hide_all (self);
1730 }
1731
1732 /**
1733  * clutter_actor_realize:
1734  * @self: A #ClutterActor
1735  *
1736  * Realization informs the actor that it is attached to a stage. It
1737  * can use this to allocate resources if it wanted to delay allocation
1738  * until it would be rendered. However it is perfectly acceptable for
1739  * an actor to create resources before being realized because Clutter
1740  * only ever has a single rendering context so that actor is free to
1741  * be moved from one stage to another.
1742  *
1743  * This function does nothing if the actor is already realized.
1744  *
1745  * Because a realized actor must have realized parent actors, calling
1746  * clutter_actor_realize() will also realize all parents of the actor.
1747  *
1748  * This function does not realize child actors, except in the special
1749  * case that realizing the stage, when the stage is visible, will
1750  * suddenly map (and thus realize) the children of the stage.
1751  **/
1752 void
1753 clutter_actor_realize (ClutterActor *self)
1754 {
1755   ClutterActorPrivate *priv;
1756
1757   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1758
1759   priv = self->priv;
1760
1761 #ifdef CLUTTER_ENABLE_DEBUG
1762   clutter_actor_verify_map_state (self);
1763 #endif
1764
1765   if (CLUTTER_ACTOR_IS_REALIZED (self))
1766     return;
1767
1768   /* To be realized, our parent actors must be realized first.
1769    * This will only succeed if we're inside a toplevel.
1770    */
1771   if (priv->parent != NULL)
1772     clutter_actor_realize (priv->parent);
1773
1774   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1775     {
1776       /* toplevels can be realized at any time */
1777     }
1778   else
1779     {
1780       /* "Fail" the realization if parent is missing or unrealized;
1781        * this should really be a g_warning() not some kind of runtime
1782        * failure; how can an app possibly recover? Instead it's a bug
1783        * in the app and the app should get an explanatory warning so
1784        * someone can fix it. But for now it's too hard to fix this
1785        * because e.g. ClutterTexture needs reworking.
1786        */
1787       if (priv->parent == NULL ||
1788           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1789         return;
1790     }
1791
1792   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1793
1794   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1795   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1796
1797   g_signal_emit (self, actor_signals[REALIZE], 0);
1798
1799   /* Stage actor is allowed to unset the realized flag again in its
1800    * default signal handler, though that is a pathological situation.
1801    */
1802
1803   /* If realization "failed" we'll have to update child state. */
1804   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1805 }
1806
1807 static void
1808 clutter_actor_real_unrealize (ClutterActor *self)
1809 {
1810   /* we must be unmapped (implying our children are also unmapped) */
1811   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1812 }
1813
1814 /**
1815  * clutter_actor_unrealize:
1816  * @self: A #ClutterActor
1817  *
1818  * Unrealization informs the actor that it may be being destroyed or
1819  * moved to another stage. The actor may want to destroy any
1820  * underlying graphics resources at this point. However it is
1821  * perfectly acceptable for it to retain the resources until the actor
1822  * is destroyed because Clutter only ever uses a single rendering
1823  * context and all of the graphics resources are valid on any stage.
1824  *
1825  * Because mapped actors must be realized, actors may not be
1826  * unrealized if they are mapped. This function hides the actor to be
1827  * sure it isn't mapped, an application-visible side effect that you
1828  * may not be expecting.
1829  *
1830  * This function should not be called by application code.
1831  */
1832 void
1833 clutter_actor_unrealize (ClutterActor *self)
1834 {
1835   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1836   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1837
1838 /* This function should not really be in the public API, because
1839  * there isn't a good reason to call it. ClutterActor will already
1840  * unrealize things for you when it's important to do so.
1841  *
1842  * If you were using clutter_actor_unrealize() in a dispose
1843  * implementation, then don't, just chain up to ClutterActor's
1844  * dispose.
1845  *
1846  * If you were using clutter_actor_unrealize() to implement
1847  * unrealizing children of your container, then don't, ClutterActor
1848  * will already take care of that.
1849  *
1850  * If you were using clutter_actor_unrealize() to re-realize to
1851  * create your resources in a different way, then use
1852  * _clutter_actor_rerealize() (inside Clutter) or just call your
1853  * code that recreates your resources directly (outside Clutter).
1854  */
1855
1856 #ifdef CLUTTER_ENABLE_DEBUG
1857   clutter_actor_verify_map_state (self);
1858 #endif
1859
1860   clutter_actor_hide (self);
1861
1862   clutter_actor_unrealize_not_hiding (self);
1863 }
1864
1865 static ClutterActorTraverseVisitFlags
1866 unrealize_actor_before_children_cb (ClutterActor *self,
1867                                     int depth,
1868                                     void *user_data)
1869 {
1870   /* If an actor is already unrealized we know its children have also
1871    * already been unrealized... */
1872   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1873     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1874
1875   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1876
1877   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1878 }
1879
1880 static ClutterActorTraverseVisitFlags
1881 unrealize_actor_after_children_cb (ClutterActor *self,
1882                                    int depth,
1883                                    void *user_data)
1884 {
1885   /* We want to unset the realized flag only _after_
1886    * child actors are unrealized, to maintain invariants.
1887    */
1888   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1889   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1890   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1891 }
1892
1893 /*
1894  * clutter_actor_unrealize_not_hiding:
1895  * @self: A #ClutterActor
1896  *
1897  * Unrealization informs the actor that it may be being destroyed or
1898  * moved to another stage. The actor may want to destroy any
1899  * underlying graphics resources at this point. However it is
1900  * perfectly acceptable for it to retain the resources until the actor
1901  * is destroyed because Clutter only ever uses a single rendering
1902  * context and all of the graphics resources are valid on any stage.
1903  *
1904  * Because mapped actors must be realized, actors may not be
1905  * unrealized if they are mapped. You must hide the actor or one of
1906  * its parents before attempting to unrealize.
1907  *
1908  * This function is separate from clutter_actor_unrealize() because it
1909  * does not automatically hide the actor.
1910  * Actors need not be hidden to be unrealized, they just need to
1911  * be unmapped. In fact we don't want to mess up the application's
1912  * setting of the "visible" flag, so hiding is very undesirable.
1913  *
1914  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1915  * backward compatibility.
1916  */
1917 static void
1918 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1919 {
1920   _clutter_actor_traverse (self,
1921                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1922                            unrealize_actor_before_children_cb,
1923                            unrealize_actor_after_children_cb,
1924                            NULL);
1925 }
1926
1927 /*
1928  * _clutter_actor_rerealize:
1929  * @self: A #ClutterActor
1930  * @callback: Function to call while unrealized
1931  * @data: data for callback
1932  *
1933  * If an actor is already unrealized, this just calls the callback.
1934  *
1935  * If it is realized, it unrealizes temporarily, calls the callback,
1936  * and then re-realizes the actor.
1937  *
1938  * As a side effect, leaves all children of the actor unrealized if
1939  * the actor was realized but not showing.  This is because when we
1940  * unrealize the actor temporarily we must unrealize its children
1941  * (e.g. children of a stage can't be realized if stage window is
1942  * gone). And we aren't clever enough to save the realization state of
1943  * all children. In most cases this should not matter, because
1944  * the children will automatically realize when they next become mapped.
1945  */
1946 void
1947 _clutter_actor_rerealize (ClutterActor    *self,
1948                           ClutterCallback  callback,
1949                           void            *data)
1950 {
1951   gboolean was_mapped;
1952   gboolean was_showing;
1953   gboolean was_realized;
1954
1955   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1956
1957 #ifdef CLUTTER_ENABLE_DEBUG
1958   clutter_actor_verify_map_state (self);
1959 #endif
1960
1961   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1962   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1963   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1964
1965   /* Must be unmapped to unrealize. Note we only have to hide this
1966    * actor if it was mapped (if all parents were showing).  If actor
1967    * is merely visible (but not mapped), then that's fine, we can
1968    * leave it visible.
1969    */
1970   if (was_mapped)
1971     clutter_actor_hide (self);
1972
1973   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1974
1975   /* unrealize self and all children */
1976   clutter_actor_unrealize_not_hiding (self);
1977
1978   if (callback != NULL)
1979     {
1980       (* callback) (self, data);
1981     }
1982
1983   if (was_showing)
1984     clutter_actor_show (self); /* will realize only if mapping implies it */
1985   else if (was_realized)
1986     clutter_actor_realize (self); /* realize self and all parents */
1987 }
1988
1989 static void
1990 clutter_actor_real_pick (ClutterActor       *self,
1991                          const ClutterColor *color)
1992 {
1993   /* the default implementation is just to paint a rectangle
1994    * with the same size of the actor using the passed color
1995    */
1996   if (clutter_actor_should_pick_paint (self))
1997     {
1998       ClutterActorBox box = { 0, };
1999       float width, height;
2000
2001       clutter_actor_get_allocation_box (self, &box);
2002
2003       width = box.x2 - box.x1;
2004       height = box.y2 - box.y1;
2005
2006       cogl_set_source_color4ub (color->red,
2007                                 color->green,
2008                                 color->blue,
2009                                 color->alpha);
2010
2011       cogl_rectangle (0, 0, width, height);
2012     }
2013
2014   /* XXX - this thoroughly sucks, but we need to maintain compatibility
2015    * with existing container classes that override the pick() virtual
2016    * and chain up to the default implementation - otherwise we'll end up
2017    * painting our children twice.
2018    *
2019    * this has to go away for 2.0; hopefully along the pick() itself.
2020    */
2021   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2022     {
2023       ClutterActor *iter;
2024
2025       for (iter = self->priv->first_child;
2026            iter != NULL;
2027            iter = iter->priv->next_sibling)
2028         clutter_actor_paint (iter);
2029     }
2030 }
2031
2032 /**
2033  * clutter_actor_should_pick_paint:
2034  * @self: A #ClutterActor
2035  *
2036  * Should be called inside the implementation of the
2037  * #ClutterActor::pick virtual function in order to check whether
2038  * the actor should paint itself in pick mode or not.
2039  *
2040  * This function should never be called directly by applications.
2041  *
2042  * Return value: %TRUE if the actor should paint its silhouette,
2043  *   %FALSE otherwise
2044  */
2045 gboolean
2046 clutter_actor_should_pick_paint (ClutterActor *self)
2047 {
2048   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2049
2050   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2051       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2052        CLUTTER_ACTOR_IS_REACTIVE (self)))
2053     return TRUE;
2054
2055   return FALSE;
2056 }
2057
2058 static void
2059 clutter_actor_real_get_preferred_width (ClutterActor *self,
2060                                         gfloat        for_height,
2061                                         gfloat       *min_width_p,
2062                                         gfloat       *natural_width_p)
2063 {
2064   ClutterActorPrivate *priv = self->priv;
2065
2066   if (priv->n_children != 0 &&
2067       priv->layout_manager != NULL)
2068     {
2069       ClutterContainer *container = CLUTTER_CONTAINER (self);
2070
2071       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2072                     "for the preferred width",
2073                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2074                     priv->layout_manager);
2075
2076       clutter_layout_manager_get_preferred_width (priv->layout_manager,
2077                                                   container,
2078                                                   for_height,
2079                                                   min_width_p,
2080                                                   natural_width_p);
2081
2082       return;
2083     }
2084
2085   /* Default implementation is always 0x0, usually an actor
2086    * using this default is relying on someone to set the
2087    * request manually
2088    */
2089   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2090
2091   if (min_width_p)
2092     *min_width_p = 0;
2093
2094   if (natural_width_p)
2095     *natural_width_p = 0;
2096 }
2097
2098 static void
2099 clutter_actor_real_get_preferred_height (ClutterActor *self,
2100                                          gfloat        for_width,
2101                                          gfloat       *min_height_p,
2102                                          gfloat       *natural_height_p)
2103 {
2104   ClutterActorPrivate *priv = self->priv;
2105
2106   if (priv->n_children != 0 &&
2107       priv->layout_manager != NULL)
2108     {
2109       ClutterContainer *container = CLUTTER_CONTAINER (self);
2110
2111       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2112                     "for the preferred height",
2113                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2114                     priv->layout_manager);
2115
2116       clutter_layout_manager_get_preferred_height (priv->layout_manager,
2117                                                    container,
2118                                                    for_width,
2119                                                    min_height_p,
2120                                                    natural_height_p);
2121
2122       return;
2123     }
2124   /* Default implementation is always 0x0, usually an actor
2125    * using this default is relying on someone to set the
2126    * request manually
2127    */
2128   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2129
2130   if (min_height_p)
2131     *min_height_p = 0;
2132
2133   if (natural_height_p)
2134     *natural_height_p = 0;
2135 }
2136
2137 static void
2138 clutter_actor_store_old_geometry (ClutterActor    *self,
2139                                   ClutterActorBox *box)
2140 {
2141   *box = self->priv->allocation;
2142 }
2143
2144 static inline void
2145 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2146                                           const ClutterActorBox *old)
2147 {
2148   ClutterActorPrivate *priv = self->priv;
2149   GObject *obj = G_OBJECT (self);
2150
2151   g_object_freeze_notify (obj);
2152
2153   /* to avoid excessive requisition or allocation cycles we
2154    * use the cached values.
2155    *
2156    * - if we don't have an allocation we assume that we need
2157    *   to notify anyway
2158    * - if we don't have a width or a height request we notify
2159    *   width and height
2160    * - if we have a valid allocation then we check the old
2161    *   bounding box with the current allocation and we notify
2162    *   the changes
2163    */
2164   if (priv->needs_allocation)
2165     {
2166       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2167       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2168       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2169       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2170     }
2171   else if (priv->needs_width_request || priv->needs_height_request)
2172     {
2173       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2174       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2175     }
2176   else
2177     {
2178       gfloat x, y;
2179       gfloat width, height;
2180
2181       x = priv->allocation.x1;
2182       y = priv->allocation.y1;
2183       width = priv->allocation.x2 - priv->allocation.x1;
2184       height = priv->allocation.y2 - priv->allocation.y1;
2185
2186       if (x != old->x1)
2187         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2188
2189       if (y != old->y1)
2190         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2191
2192       if (width != (old->x2 - old->x1))
2193         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2194
2195       if (height != (old->y2 - old->y1))
2196         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2197     }
2198
2199   g_object_thaw_notify (obj);
2200 }
2201
2202 /*< private >
2203  * clutter_actor_set_allocation_internal:
2204  * @self: a #ClutterActor
2205  * @box: a #ClutterActorBox
2206  * @flags: allocation flags
2207  *
2208  * Stores the allocation of @self.
2209  *
2210  * This function only performs basic storage and property notification.
2211  *
2212  * This function should be called by clutter_actor_set_allocation()
2213  * and by the default implementation of #ClutterActorClass.allocate().
2214  *
2215  * Return value: %TRUE if the allocation of the #ClutterActor has been
2216  *   changed, and %FALSE otherwise
2217  */
2218 static inline gboolean
2219 clutter_actor_set_allocation_internal (ClutterActor           *self,
2220                                        const ClutterActorBox  *box,
2221                                        ClutterAllocationFlags  flags)
2222 {
2223   ClutterActorPrivate *priv = self->priv;
2224   GObject *obj;
2225   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2226   gboolean flags_changed;
2227   gboolean retval;
2228   ClutterActorBox old_alloc = { 0, };
2229
2230   obj = G_OBJECT (self);
2231
2232   g_object_freeze_notify (obj);
2233
2234   clutter_actor_store_old_geometry (self, &old_alloc);
2235
2236   x1_changed = priv->allocation.x1 != box->x1;
2237   y1_changed = priv->allocation.y1 != box->y1;
2238   x2_changed = priv->allocation.x2 != box->x2;
2239   y2_changed = priv->allocation.y2 != box->y2;
2240
2241   flags_changed = priv->allocation_flags != flags;
2242
2243   priv->allocation = *box;
2244   priv->allocation_flags = flags;
2245
2246   /* allocation is authoritative */
2247   priv->needs_width_request = FALSE;
2248   priv->needs_height_request = FALSE;
2249   priv->needs_allocation = FALSE;
2250
2251   if (x1_changed || y1_changed ||
2252       x2_changed || y2_changed ||
2253       flags_changed)
2254     {
2255       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2256                     _clutter_actor_get_debug_name (self));
2257
2258       priv->transform_valid = FALSE;
2259
2260       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2261
2262       /* if the allocation changes, so does the content box */
2263       if (priv->content != NULL)
2264         {
2265           priv->content_box_valid = FALSE;
2266           g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2267         }
2268
2269       retval = TRUE;
2270     }
2271   else
2272     retval = FALSE;
2273
2274   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2275
2276   g_object_thaw_notify (obj);
2277
2278   return retval;
2279 }
2280
2281 static void clutter_actor_real_allocate (ClutterActor           *self,
2282                                          const ClutterActorBox  *box,
2283                                          ClutterAllocationFlags  flags);
2284
2285 static inline void
2286 clutter_actor_maybe_layout_children (ClutterActor           *self,
2287                                      const ClutterActorBox  *allocation,
2288                                      ClutterAllocationFlags  flags)
2289 {
2290   ClutterActorPrivate *priv = self->priv;
2291
2292   /* this is going to be a bit hard to follow, so let's put an explanation
2293    * here.
2294    *
2295    * we want ClutterActor to have a default layout manager if the actor was
2296    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2297    *
2298    * we also want any subclass of ClutterActor that does not override the
2299    * ::allocate() virtual function to delegate to a layout manager.
2300    *
2301    * finally, we want to allow people subclassing ClutterActor and overriding
2302    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2303    *
2304    * on the other hand, we want existing actor subclasses overriding the
2305    * ::allocate() virtual function and chaining up to the parent's
2306    * implementation to continue working without allocating their children
2307    * twice, or without entering an allocation loop.
2308    *
2309    * for the first two points, we check if the class of the actor is
2310    * overridding the ::allocate() virtual function; if it isn't, then we
2311    * follow through with checking whether we have children and a layout
2312    * manager, and eventually calling clutter_layout_manager_allocate().
2313    *
2314    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2315    * allocation flags that we got passed, and if it is present, we continue
2316    * with the check above.
2317    *
2318    * if neither of these two checks yields a positive result, we just
2319    * assume that the ::allocate() virtual function that resulted in this
2320    * function being called will also allocate the children of the actor.
2321    */
2322
2323   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2324     goto check_layout;
2325
2326   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2327     goto check_layout;
2328
2329   return;
2330
2331 check_layout:
2332   if (priv->n_children != 0 &&
2333       priv->layout_manager != NULL)
2334     {
2335       ClutterContainer *container = CLUTTER_CONTAINER (self);
2336       ClutterAllocationFlags children_flags;
2337       ClutterActorBox children_box;
2338
2339       /* normalize the box passed to the layout manager */
2340       children_box.x1 = children_box.y1 = 0.f;
2341       children_box.x2 = (allocation->x2 - allocation->x1);
2342       children_box.y2 = (allocation->y2 - allocation->y1);
2343
2344       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2345        * the actor's children, since it refers only to the current
2346        * actor's allocation.
2347        */
2348       children_flags = flags;
2349       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2350
2351       CLUTTER_NOTE (LAYOUT,
2352                     "Allocating %d children of %s "
2353                     "at { %.2f, %.2f - %.2f x %.2f } "
2354                     "using %s",
2355                     priv->n_children,
2356                     _clutter_actor_get_debug_name (self),
2357                     allocation->x1,
2358                     allocation->y1,
2359                     (allocation->x2 - allocation->x1),
2360                     (allocation->y2 - allocation->y1),
2361                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2362
2363       clutter_layout_manager_allocate (priv->layout_manager,
2364                                        container,
2365                                        &children_box,
2366                                        children_flags);
2367     }
2368 }
2369
2370 static void
2371 clutter_actor_real_allocate (ClutterActor           *self,
2372                              const ClutterActorBox  *box,
2373                              ClutterAllocationFlags  flags)
2374 {
2375   ClutterActorPrivate *priv = self->priv;
2376   gboolean changed;
2377
2378   g_object_freeze_notify (G_OBJECT (self));
2379
2380   changed = clutter_actor_set_allocation_internal (self, box, flags);
2381
2382   /* we allocate our children before we notify changes in our geometry,
2383    * so that people connecting to properties will be able to get valid
2384    * data out of the sub-tree of the scene graph that has this actor at
2385    * the root.
2386    */
2387   clutter_actor_maybe_layout_children (self, box, flags);
2388
2389   if (changed)
2390     {
2391       ClutterActorBox signal_box = priv->allocation;
2392       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2393
2394       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2395                      &signal_box,
2396                      signal_flags);
2397     }
2398
2399   g_object_thaw_notify (G_OBJECT (self));
2400 }
2401
2402 static void
2403 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2404                                     ClutterActor *origin)
2405 {
2406   /* no point in queuing a redraw on a destroyed actor */
2407   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2408     return;
2409
2410   /* NB: We can't bail out early here if the actor is hidden in case
2411    * the actor bas been cloned. In this case the clone will need to
2412    * receive the signal so it can queue its own redraw.
2413    */
2414
2415   /* calls klass->queue_redraw in default handler */
2416   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2417 }
2418
2419 static void
2420 clutter_actor_real_queue_redraw (ClutterActor *self,
2421                                  ClutterActor *origin)
2422 {
2423   ClutterActor *parent;
2424
2425   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2426                 _clutter_actor_get_debug_name (self),
2427                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2428                                : "same actor");
2429
2430   /* no point in queuing a redraw on a destroyed actor */
2431   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2432     return;
2433
2434   /* If the queue redraw is coming from a child then the actor has
2435      become dirty and any queued effect is no longer valid */
2436   if (self != origin)
2437     {
2438       self->priv->is_dirty = TRUE;
2439       self->priv->effect_to_redraw = NULL;
2440     }
2441
2442   /* If the actor isn't visible, we still had to emit the signal
2443    * to allow for a ClutterClone, but the appearance of the parent
2444    * won't change so we don't have to propagate up the hierarchy.
2445    */
2446   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2447     return;
2448
2449   /* Although we could determine here that a full stage redraw
2450    * has already been queued and immediately bail out, we actually
2451    * guarantee that we will propagate a queue-redraw signal to our
2452    * parent at least once so that it's possible to implement a
2453    * container that tracks which of its children have queued a
2454    * redraw.
2455    */
2456   if (self->priv->propagated_one_redraw)
2457     {
2458       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2459       if (stage != NULL &&
2460           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2461         return;
2462     }
2463
2464   self->priv->propagated_one_redraw = TRUE;
2465
2466   /* notify parents, if they are all visible eventually we'll
2467    * queue redraw on the stage, which queues the redraw idle.
2468    */
2469   parent = clutter_actor_get_parent (self);
2470   if (parent != NULL)
2471     {
2472       /* this will go up recursively */
2473       _clutter_actor_signal_queue_redraw (parent, origin);
2474     }
2475 }
2476
2477 static void
2478 clutter_actor_real_queue_relayout (ClutterActor *self)
2479 {
2480   ClutterActorPrivate *priv = self->priv;
2481
2482   /* no point in queueing a redraw on a destroyed actor */
2483   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2484     return;
2485
2486   priv->needs_width_request  = TRUE;
2487   priv->needs_height_request = TRUE;
2488   priv->needs_allocation     = TRUE;
2489
2490   /* reset the cached size requests */
2491   memset (priv->width_requests, 0,
2492           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2493   memset (priv->height_requests, 0,
2494           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2495
2496   /* We need to go all the way up the hierarchy */
2497   if (priv->parent != NULL)
2498     _clutter_actor_queue_only_relayout (priv->parent);
2499 }
2500
2501 /**
2502  * clutter_actor_apply_relative_transform_to_point:
2503  * @self: A #ClutterActor
2504  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2505  *   default #ClutterStage
2506  * @point: A point as #ClutterVertex
2507  * @vertex: (out caller-allocates): The translated #ClutterVertex
2508  *
2509  * Transforms @point in coordinates relative to the actor into
2510  * ancestor-relative coordinates using the relevant transform
2511  * stack (i.e. scale, rotation, etc).
2512  *
2513  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2514  * this case, the coordinates returned will be the coordinates on
2515  * the stage before the projection is applied. This is different from
2516  * the behaviour of clutter_actor_apply_transform_to_point().
2517  *
2518  * Since: 0.6
2519  */
2520 void
2521 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2522                                                  ClutterActor        *ancestor,
2523                                                  const ClutterVertex *point,
2524                                                  ClutterVertex       *vertex)
2525 {
2526   gfloat w;
2527   CoglMatrix matrix;
2528
2529   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2530   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2531   g_return_if_fail (point != NULL);
2532   g_return_if_fail (vertex != NULL);
2533
2534   *vertex = *point;
2535   w = 1.0;
2536
2537   if (ancestor == NULL)
2538     ancestor = _clutter_actor_get_stage_internal (self);
2539
2540   if (ancestor == NULL)
2541     {
2542       *vertex = *point;
2543       return;
2544     }
2545
2546   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2547   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2548 }
2549
2550 static gboolean
2551 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2552                                          const ClutterVertex *vertices_in,
2553                                          ClutterVertex *vertices_out,
2554                                          int n_vertices)
2555 {
2556   ClutterActor *stage;
2557   CoglMatrix modelview;
2558   CoglMatrix projection;
2559   float viewport[4];
2560
2561   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2562
2563   stage = _clutter_actor_get_stage_internal (self);
2564
2565   /* We really can't do anything meaningful in this case so don't try
2566    * to do any transform */
2567   if (stage == NULL)
2568     return FALSE;
2569
2570   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2571    * that gets us to stage coordinates, we want to go all the way to eye
2572    * coordinates */
2573   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2574
2575   /* Fetch the projection and viewport */
2576   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2577   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2578                                &viewport[0],
2579                                &viewport[1],
2580                                &viewport[2],
2581                                &viewport[3]);
2582
2583   _clutter_util_fully_transform_vertices (&modelview,
2584                                           &projection,
2585                                           viewport,
2586                                           vertices_in,
2587                                           vertices_out,
2588                                           n_vertices);
2589
2590   return TRUE;
2591 }
2592
2593 /**
2594  * clutter_actor_apply_transform_to_point:
2595  * @self: A #ClutterActor
2596  * @point: A point as #ClutterVertex
2597  * @vertex: (out caller-allocates): The translated #ClutterVertex
2598  *
2599  * Transforms @point in coordinates relative to the actor
2600  * into screen-relative coordinates with the current actor
2601  * transformation (i.e. scale, rotation, etc)
2602  *
2603  * Since: 0.4
2604  **/
2605 void
2606 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2607                                         const ClutterVertex *point,
2608                                         ClutterVertex       *vertex)
2609 {
2610   g_return_if_fail (point != NULL);
2611   g_return_if_fail (vertex != NULL);
2612   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2613 }
2614
2615 /*
2616  * _clutter_actor_get_relative_transformation_matrix:
2617  * @self: The actor whose coordinate space you want to transform from.
2618  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2619  *            or %NULL if you want to transform all the way to eye coordinates.
2620  * @matrix: A #CoglMatrix to store the transformation
2621  *
2622  * This gets a transformation @matrix that will transform coordinates from the
2623  * coordinate space of @self into the coordinate space of @ancestor.
2624  *
2625  * For example if you need a matrix that can transform the local actor
2626  * coordinates of @self into stage coordinates you would pass the actor's stage
2627  * pointer as the @ancestor.
2628  *
2629  * If you pass %NULL then the transformation will take you all the way through
2630  * to eye coordinates. This can be useful if you want to extract the entire
2631  * modelview transform that Clutter applies before applying the projection
2632  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2633  * using cogl_set_modelview_matrix() for example then you would want a matrix
2634  * that transforms into eye coordinates.
2635  *
2636  * <note><para>This function explicitly initializes the given @matrix. If you just
2637  * want clutter to multiply a relative transformation with an existing matrix
2638  * you can use clutter_actor_apply_relative_transformation_matrix()
2639  * instead.</para></note>
2640  *
2641  */
2642 /* XXX: We should consider caching the stage relative modelview along with
2643  * the actor itself */
2644 static void
2645 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2646                                                    ClutterActor *ancestor,
2647                                                    CoglMatrix *matrix)
2648 {
2649   cogl_matrix_init_identity (matrix);
2650
2651   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2652 }
2653
2654 /* Project the given @box into stage window coordinates, writing the
2655  * transformed vertices to @verts[]. */
2656 static gboolean
2657 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2658                                           const ClutterActorBox *box,
2659                                           ClutterVertex          verts[])
2660 {
2661   ClutterVertex box_vertices[4];
2662
2663   box_vertices[0].x = box->x1;
2664   box_vertices[0].y = box->y1;
2665   box_vertices[0].z = 0;
2666   box_vertices[1].x = box->x2;
2667   box_vertices[1].y = box->y1;
2668   box_vertices[1].z = 0;
2669   box_vertices[2].x = box->x1;
2670   box_vertices[2].y = box->y2;
2671   box_vertices[2].z = 0;
2672   box_vertices[3].x = box->x2;
2673   box_vertices[3].y = box->y2;
2674   box_vertices[3].z = 0;
2675
2676   return
2677     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2678 }
2679
2680 /**
2681  * clutter_actor_get_allocation_vertices:
2682  * @self: A #ClutterActor
2683  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2684  *   against, or %NULL to use the #ClutterStage
2685  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2686  *   location for an array of 4 #ClutterVertex in which to store the result
2687  *
2688  * Calculates the transformed coordinates of the four corners of the
2689  * actor in the plane of @ancestor. The returned vertices relate to
2690  * the #ClutterActorBox coordinates as follows:
2691  * <itemizedlist>
2692  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2693  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2694  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2695  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2696  * </itemizedlist>
2697  *
2698  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2699  * this case, the coordinates returned will be the coordinates on
2700  * the stage before the projection is applied. This is different from
2701  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2702  *
2703  * Since: 0.6
2704  */
2705 void
2706 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2707                                        ClutterActor  *ancestor,
2708                                        ClutterVertex  verts[])
2709 {
2710   ClutterActorPrivate *priv;
2711   ClutterActorBox box;
2712   ClutterVertex vertices[4];
2713   CoglMatrix modelview;
2714
2715   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2716   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2717
2718   if (ancestor == NULL)
2719     ancestor = _clutter_actor_get_stage_internal (self);
2720
2721   /* Fallback to a NOP transform if the actor isn't parented under a
2722    * stage. */
2723   if (ancestor == NULL)
2724     ancestor = self;
2725
2726   priv = self->priv;
2727
2728   /* if the actor needs to be allocated we force a relayout, so that
2729    * we will have valid values to use in the transformations */
2730   if (priv->needs_allocation)
2731     {
2732       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2733       if (stage)
2734         _clutter_stage_maybe_relayout (stage);
2735       else
2736         {
2737           box.x1 = box.y1 = 0;
2738           /* The result isn't really meaningful in this case but at
2739            * least try to do something *vaguely* reasonable... */
2740           clutter_actor_get_size (self, &box.x2, &box.y2);
2741         }
2742     }
2743
2744   clutter_actor_get_allocation_box (self, &box);
2745
2746   vertices[0].x = box.x1;
2747   vertices[0].y = box.y1;
2748   vertices[0].z = 0;
2749   vertices[1].x = box.x2;
2750   vertices[1].y = box.y1;
2751   vertices[1].z = 0;
2752   vertices[2].x = box.x1;
2753   vertices[2].y = box.y2;
2754   vertices[2].z = 0;
2755   vertices[3].x = box.x2;
2756   vertices[3].y = box.y2;
2757   vertices[3].z = 0;
2758
2759   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2760                                                      &modelview);
2761
2762   cogl_matrix_transform_points (&modelview,
2763                                 3,
2764                                 sizeof (ClutterVertex),
2765                                 vertices,
2766                                 sizeof (ClutterVertex),
2767                                 vertices,
2768                                 4);
2769 }
2770
2771 /**
2772  * clutter_actor_get_abs_allocation_vertices:
2773  * @self: A #ClutterActor
2774  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2775  *   of 4 #ClutterVertex where to store the result.
2776  *
2777  * Calculates the transformed screen coordinates of the four corners of
2778  * the actor; the returned vertices relate to the #ClutterActorBox
2779  * coordinates  as follows:
2780  * <itemizedlist>
2781  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2782  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2783  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2784  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2785  * </itemizedlist>
2786  *
2787  * Since: 0.4
2788  */
2789 void
2790 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2791                                            ClutterVertex  verts[])
2792 {
2793   ClutterActorPrivate *priv;
2794   ClutterActorBox actor_space_allocation;
2795
2796   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2797
2798   priv = self->priv;
2799
2800   /* if the actor needs to be allocated we force a relayout, so that
2801    * the actor allocation box will be valid for
2802    * _clutter_actor_transform_and_project_box()
2803    */
2804   if (priv->needs_allocation)
2805     {
2806       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2807       /* There's nothing meaningful we can do now */
2808       if (!stage)
2809         return;
2810
2811       _clutter_stage_maybe_relayout (stage);
2812     }
2813
2814   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2815    * own coordinate space... */
2816   actor_space_allocation.x1 = 0;
2817   actor_space_allocation.y1 = 0;
2818   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2819   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2820   _clutter_actor_transform_and_project_box (self,
2821                                             &actor_space_allocation,
2822                                             verts);
2823 }
2824
2825 static void
2826 clutter_actor_real_apply_transform (ClutterActor *self,
2827                                     CoglMatrix   *matrix)
2828 {
2829   ClutterActorPrivate *priv = self->priv;
2830
2831   if (!priv->transform_valid)
2832     {
2833       CoglMatrix *transform = &priv->transform;
2834       const ClutterTransformInfo *info;
2835
2836       info = _clutter_actor_get_transform_info_or_defaults (self);
2837
2838       cogl_matrix_init_identity (transform);
2839
2840       cogl_matrix_translate (transform,
2841                              priv->allocation.x1,
2842                              priv->allocation.y1,
2843                              0.0);
2844
2845       if (info->depth)
2846         cogl_matrix_translate (transform, 0, 0, info->depth);
2847
2848       /*
2849        * because the rotation involves translations, we must scale
2850        * before applying the rotations (if we apply the scale after
2851        * the rotations, the translations included in the rotation are
2852        * not scaled and so the entire object will move on the screen
2853        * as a result of rotating it).
2854        */
2855       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2856         {
2857           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2858                                         &info->scale_center,
2859                                         cogl_matrix_scale (transform,
2860                                                            info->scale_x,
2861                                                            info->scale_y,
2862                                                            1.0));
2863         }
2864
2865       if (info->rz_angle)
2866         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2867                                       &info->rz_center,
2868                                       cogl_matrix_rotate (transform,
2869                                                           info->rz_angle,
2870                                                           0, 0, 1.0));
2871
2872       if (info->ry_angle)
2873         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2874                                       &info->ry_center,
2875                                       cogl_matrix_rotate (transform,
2876                                                           info->ry_angle,
2877                                                           0, 1.0, 0));
2878
2879       if (info->rx_angle)
2880         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2881                                       &info->rx_center,
2882                                       cogl_matrix_rotate (transform,
2883                                                           info->rx_angle,
2884                                                           1.0, 0, 0));
2885
2886       if (!clutter_anchor_coord_is_zero (&info->anchor))
2887         {
2888           gfloat x, y, z;
2889
2890           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2891           cogl_matrix_translate (transform, -x, -y, -z);
2892         }
2893
2894       priv->transform_valid = TRUE;
2895     }
2896
2897   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2898 }
2899
2900 /* Applies the transforms associated with this actor to the given
2901  * matrix. */
2902 void
2903 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2904                                           CoglMatrix *matrix)
2905 {
2906   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2907 }
2908
2909 /*
2910  * clutter_actor_apply_relative_transformation_matrix:
2911  * @self: The actor whose coordinate space you want to transform from.
2912  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2913  *            or %NULL if you want to transform all the way to eye coordinates.
2914  * @matrix: A #CoglMatrix to apply the transformation too.
2915  *
2916  * This multiplies a transform with @matrix that will transform coordinates
2917  * from the coordinate space of @self into the coordinate space of @ancestor.
2918  *
2919  * For example if you need a matrix that can transform the local actor
2920  * coordinates of @self into stage coordinates you would pass the actor's stage
2921  * pointer as the @ancestor.
2922  *
2923  * If you pass %NULL then the transformation will take you all the way through
2924  * to eye coordinates. This can be useful if you want to extract the entire
2925  * modelview transform that Clutter applies before applying the projection
2926  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2927  * using cogl_set_modelview_matrix() for example then you would want a matrix
2928  * that transforms into eye coordinates.
2929  *
2930  * <note>This function doesn't initialize the given @matrix, it simply
2931  * multiplies the requested transformation matrix with the existing contents of
2932  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2933  * before calling this function, or you can use
2934  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2935  */
2936 void
2937 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2938                                                      ClutterActor *ancestor,
2939                                                      CoglMatrix *matrix)
2940 {
2941   ClutterActor *parent;
2942
2943   /* Note we terminate before ever calling stage->apply_transform()
2944    * since that would conceptually be relative to the underlying
2945    * window OpenGL coordinates so we'd need a special @ancestor
2946    * value to represent the fake parent of the stage. */
2947   if (self == ancestor)
2948     return;
2949
2950   parent = clutter_actor_get_parent (self);
2951
2952   if (parent != NULL)
2953     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2954                                                          matrix);
2955
2956   _clutter_actor_apply_modelview_transform (self, matrix);
2957 }
2958
2959 static void
2960 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2961                                        ClutterPaintVolume *pv,
2962                                        const char *label,
2963                                        const CoglColor *color)
2964 {
2965   static CoglPipeline *outline = NULL;
2966   CoglPrimitive *prim;
2967   ClutterVertex line_ends[12 * 2];
2968   int n_vertices;
2969   CoglContext *ctx =
2970     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2971   /* XXX: at some point we'll query this from the stage but we can't
2972    * do that until the osx backend uses Cogl natively. */
2973   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2974
2975   if (outline == NULL)
2976     outline = cogl_pipeline_new (ctx);
2977
2978   _clutter_paint_volume_complete (pv);
2979
2980   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2981
2982   /* Front face */
2983   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2984   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2985   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2986   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2987
2988   if (!pv->is_2d)
2989     {
2990       /* Back face */
2991       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2992       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2993       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2994       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2995
2996       /* Lines connecting front face to back face */
2997       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2998       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2999       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3000       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3001     }
3002
3003   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3004                                 n_vertices,
3005                                 (CoglVertexP3 *)line_ends);
3006
3007   cogl_pipeline_set_color (outline, color);
3008   cogl_framebuffer_draw_primitive (fb, outline, prim);
3009   cogl_object_unref (prim);
3010
3011   if (label)
3012     {
3013       PangoLayout *layout;
3014       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3015       pango_layout_set_text (layout, label, -1);
3016       cogl_pango_render_layout (layout,
3017                                 pv->vertices[0].x,
3018                                 pv->vertices[0].y,
3019                                 color,
3020                                 0);
3021       g_object_unref (layout);
3022     }
3023 }
3024
3025 static void
3026 _clutter_actor_draw_paint_volume (ClutterActor *self)
3027 {
3028   ClutterPaintVolume *pv;
3029   CoglColor color;
3030
3031   pv = _clutter_actor_get_paint_volume_mutable (self);
3032   if (!pv)
3033     {
3034       gfloat width, height;
3035       ClutterPaintVolume fake_pv;
3036
3037       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3038       _clutter_paint_volume_init_static (&fake_pv, stage);
3039
3040       clutter_actor_get_size (self, &width, &height);
3041       clutter_paint_volume_set_width (&fake_pv, width);
3042       clutter_paint_volume_set_height (&fake_pv, height);
3043
3044       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3045       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3046                                              _clutter_actor_get_debug_name (self),
3047                                              &color);
3048
3049       clutter_paint_volume_free (&fake_pv);
3050     }
3051   else
3052     {
3053       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3054       _clutter_actor_draw_paint_volume_full (self, pv,
3055                                              _clutter_actor_get_debug_name (self),
3056                                              &color);
3057     }
3058 }
3059
3060 static void
3061 _clutter_actor_paint_cull_result (ClutterActor *self,
3062                                   gboolean success,
3063                                   ClutterCullResult result)
3064 {
3065   ClutterPaintVolume *pv;
3066   CoglColor color;
3067
3068   if (success)
3069     {
3070       if (result == CLUTTER_CULL_RESULT_IN)
3071         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3072       else if (result == CLUTTER_CULL_RESULT_OUT)
3073         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3074       else
3075         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3076     }
3077   else
3078     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3079
3080   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3081     _clutter_actor_draw_paint_volume_full (self, pv,
3082                                            _clutter_actor_get_debug_name (self),
3083                                            &color);
3084   else
3085     {
3086       PangoLayout *layout;
3087       char *label =
3088         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3089       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3090       cogl_set_source_color (&color);
3091
3092       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3093       pango_layout_set_text (layout, label, -1);
3094       cogl_pango_render_layout (layout,
3095                                 0,
3096                                 0,
3097                                 &color,
3098                                 0);
3099       g_free (label);
3100       g_object_unref (layout);
3101     }
3102 }
3103
3104 static int clone_paint_level = 0;
3105
3106 void
3107 _clutter_actor_push_clone_paint (void)
3108 {
3109   clone_paint_level++;
3110 }
3111
3112 void
3113 _clutter_actor_pop_clone_paint (void)
3114 {
3115   clone_paint_level--;
3116 }
3117
3118 static gboolean
3119 in_clone_paint (void)
3120 {
3121   return clone_paint_level > 0;
3122 }
3123
3124 /* Returns TRUE if the actor can be ignored */
3125 /* FIXME: we should return a ClutterCullResult, and
3126  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3127  * means there's no point in trying to cull descendants of the current
3128  * node. */
3129 static gboolean
3130 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3131 {
3132   ClutterActorPrivate *priv = self->priv;
3133   ClutterActor *stage;
3134   const ClutterPlane *stage_clip;
3135
3136   if (!priv->last_paint_volume_valid)
3137     {
3138       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3139                     "->last_paint_volume_valid == FALSE",
3140                     _clutter_actor_get_debug_name (self));
3141       return FALSE;
3142     }
3143
3144   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3145     return FALSE;
3146
3147   stage = _clutter_actor_get_stage_internal (self);
3148   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3149   if (G_UNLIKELY (!stage_clip))
3150     {
3151       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3152                     "No stage clip set",
3153                     _clutter_actor_get_debug_name (self));
3154       return FALSE;
3155     }
3156
3157   if (cogl_get_draw_framebuffer () !=
3158       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3159     {
3160       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3161                     "Current framebuffer doesn't correspond to stage",
3162                     _clutter_actor_get_debug_name (self));
3163       return FALSE;
3164     }
3165
3166   *result_out =
3167     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3168   return TRUE;
3169 }
3170
3171 static void
3172 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3173 {
3174   ClutterActorPrivate *priv = self->priv;
3175   const ClutterPaintVolume *pv;
3176
3177   if (priv->last_paint_volume_valid)
3178     {
3179       clutter_paint_volume_free (&priv->last_paint_volume);
3180       priv->last_paint_volume_valid = FALSE;
3181     }
3182
3183   pv = clutter_actor_get_paint_volume (self);
3184   if (!pv)
3185     {
3186       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3187                     "Actor failed to report a paint volume",
3188                     _clutter_actor_get_debug_name (self));
3189       return;
3190     }
3191
3192   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3193
3194   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3195                                             NULL); /* eye coordinates */
3196
3197   priv->last_paint_volume_valid = TRUE;
3198 }
3199
3200 static inline gboolean
3201 actor_has_shader_data (ClutterActor *self)
3202 {
3203   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3204 }
3205
3206 guint32
3207 _clutter_actor_get_pick_id (ClutterActor *self)
3208 {
3209   if (self->priv->pick_id < 0)
3210     return 0;
3211
3212   return self->priv->pick_id;
3213 }
3214
3215 /* This is the same as clutter_actor_add_effect except that it doesn't
3216    queue a redraw and it doesn't notify on the effect property */
3217 static void
3218 _clutter_actor_add_effect_internal (ClutterActor  *self,
3219                                     ClutterEffect *effect)
3220 {
3221   ClutterActorPrivate *priv = self->priv;
3222
3223   if (priv->effects == NULL)
3224     {
3225       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3226       priv->effects->actor = self;
3227     }
3228
3229   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3230 }
3231
3232 /* This is the same as clutter_actor_remove_effect except that it doesn't
3233    queue a redraw and it doesn't notify on the effect property */
3234 static void
3235 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3236                                        ClutterEffect *effect)
3237 {
3238   ClutterActorPrivate *priv = self->priv;
3239
3240   if (priv->effects == NULL)
3241     return;
3242
3243   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3244 }
3245
3246 static gboolean
3247 needs_flatten_effect (ClutterActor *self)
3248 {
3249   ClutterActorPrivate *priv = self->priv;
3250
3251   if (G_UNLIKELY (clutter_paint_debug_flags &
3252                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3253     return FALSE;
3254
3255   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3256     return TRUE;
3257   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3258     {
3259       if (clutter_actor_get_paint_opacity (self) < 255 &&
3260           clutter_actor_has_overlaps (self))
3261         return TRUE;
3262     }
3263
3264   return FALSE;
3265 }
3266
3267 static void
3268 add_or_remove_flatten_effect (ClutterActor *self)
3269 {
3270   ClutterActorPrivate *priv = self->priv;
3271
3272   /* Add or remove the flatten effect depending on the
3273      offscreen-redirect property. */
3274   if (needs_flatten_effect (self))
3275     {
3276       if (priv->flatten_effect == NULL)
3277         {
3278           ClutterActorMeta *actor_meta;
3279           gint priority;
3280
3281           priv->flatten_effect = _clutter_flatten_effect_new ();
3282           /* Keep a reference to the effect so that we can queue
3283              redraws from it */
3284           g_object_ref_sink (priv->flatten_effect);
3285
3286           /* Set the priority of the effect to high so that it will
3287              always be applied to the actor first. It uses an internal
3288              priority so that it won't be visible to applications */
3289           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3290           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3291           _clutter_actor_meta_set_priority (actor_meta, priority);
3292
3293           /* This will add the effect without queueing a redraw */
3294           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3295         }
3296     }
3297   else
3298     {
3299       if (priv->flatten_effect != NULL)
3300         {
3301           /* Destroy the effect so that it will lose its fbo cache of
3302              the actor */
3303           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3304           g_clear_object (&priv->flatten_effect);
3305         }
3306     }
3307 }
3308
3309 static void
3310 clutter_actor_real_paint (ClutterActor *actor)
3311 {
3312   ClutterActorPrivate *priv = actor->priv;
3313   ClutterActor *iter;
3314
3315   for (iter = priv->first_child;
3316        iter != NULL;
3317        iter = iter->priv->next_sibling)
3318     {
3319       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3320                     _clutter_actor_get_debug_name (iter),
3321                     _clutter_actor_get_debug_name (actor),
3322                     iter->priv->allocation.x1,
3323                     iter->priv->allocation.y1,
3324                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3325                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3326
3327       clutter_actor_paint (iter);
3328     }
3329 }
3330
3331 static gboolean
3332 clutter_actor_paint_node (ClutterActor     *actor,
3333                           ClutterPaintNode *root)
3334 {
3335   ClutterActorPrivate *priv = actor->priv;
3336
3337   if (root == NULL)
3338     return FALSE;
3339
3340   if (priv->bg_color_set &&
3341       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3342     {
3343       ClutterPaintNode *node;
3344       ClutterColor bg_color;
3345       ClutterActorBox box;
3346
3347       box.x1 = 0.f;
3348       box.y1 = 0.f;
3349       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3350       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3351
3352       bg_color = priv->bg_color;
3353       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3354                      * priv->bg_color.alpha
3355                      / 255;
3356
3357       node = clutter_color_node_new (&bg_color);
3358       clutter_paint_node_set_name (node, "backgroundColor");
3359       clutter_paint_node_add_rectangle (node, &box);
3360       clutter_paint_node_add_child (root, node);
3361       clutter_paint_node_unref (node);
3362     }
3363
3364   if (priv->content != NULL)
3365     _clutter_content_paint_content (priv->content, actor, root);
3366
3367   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3368     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3369
3370   if (clutter_paint_node_get_n_children (root) == 0)
3371     return FALSE;
3372
3373 #ifdef CLUTTER_ENABLE_DEBUG
3374   if (CLUTTER_HAS_DEBUG (PAINT))
3375     {
3376       /* dump the tree only if we have one */
3377       _clutter_paint_node_dump_tree (root);
3378     }
3379 #endif /* CLUTTER_ENABLE_DEBUG */
3380
3381   _clutter_paint_node_paint (root);
3382
3383 #if 0
3384   /* XXX: Uncomment this when we disable emitting the paint signal */
3385   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3386 #endif
3387
3388   return TRUE;
3389 }
3390
3391 /**
3392  * clutter_actor_paint:
3393  * @self: A #ClutterActor
3394  *
3395  * Renders the actor to display.
3396  *
3397  * This function should not be called directly by applications.
3398  * Call clutter_actor_queue_redraw() to queue paints, instead.
3399  *
3400  * This function is context-aware, and will either cause a
3401  * regular paint or a pick paint.
3402  *
3403  * This function will emit the #ClutterActor::paint signal or
3404  * the #ClutterActor::pick signal, depending on the context.
3405  *
3406  * This function does not paint the actor if the actor is set to 0,
3407  * unless it is performing a pick paint.
3408  */
3409 void
3410 clutter_actor_paint (ClutterActor *self)
3411 {
3412   ClutterActorPrivate *priv;
3413   ClutterPickMode pick_mode;
3414   gboolean clip_set = FALSE;
3415   gboolean shader_applied = FALSE;
3416
3417   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3418                           "Actor real-paint counter",
3419                           "Increments each time any actor is painted",
3420                           0 /* no application private data */);
3421   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3422                           "Actor pick-paint counter",
3423                           "Increments each time any actor is painted "
3424                           "for picking",
3425                           0 /* no application private data */);
3426
3427   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3428
3429   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3430     return;
3431
3432   priv = self->priv;
3433
3434   pick_mode = _clutter_context_get_pick_mode ();
3435
3436   if (pick_mode == CLUTTER_PICK_NONE)
3437     priv->propagated_one_redraw = FALSE;
3438
3439   /* It's an important optimization that we consider painting of
3440    * actors with 0 opacity to be a NOP... */
3441   if (pick_mode == CLUTTER_PICK_NONE &&
3442       /* ignore top-levels, since they might be transparent */
3443       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3444       /* Use the override opacity if its been set */
3445       ((priv->opacity_override >= 0) ?
3446        priv->opacity_override : priv->opacity) == 0)
3447     return;
3448
3449   /* if we aren't paintable (not in a toplevel with all
3450    * parents paintable) then do nothing.
3451    */
3452   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3453     return;
3454
3455   /* mark that we are in the paint process */
3456   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3457
3458   cogl_push_matrix();
3459
3460   if (priv->enable_model_view_transform)
3461     {
3462       CoglMatrix matrix;
3463
3464       /* XXX: It could be better to cache the modelview with the actor
3465        * instead of progressively building up the transformations on
3466        * the matrix stack every time we paint. */
3467       cogl_get_modelview_matrix (&matrix);
3468       _clutter_actor_apply_modelview_transform (self, &matrix);
3469
3470 #ifdef CLUTTER_ENABLE_DEBUG
3471       /* Catch when out-of-band transforms have been made by actors not as part
3472        * of an apply_transform vfunc... */
3473       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3474         {
3475           CoglMatrix expected_matrix;
3476
3477           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3478                                                              &expected_matrix);
3479
3480           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3481             {
3482               GString *buf = g_string_sized_new (1024);
3483               ClutterActor *parent;
3484
3485               parent = self;
3486               while (parent != NULL)
3487                 {
3488                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3489
3490                   if (parent->priv->parent != NULL)
3491                     g_string_append (buf, "->");
3492
3493                   parent = parent->priv->parent;
3494                 }
3495
3496               g_warning ("Unexpected transform found when painting actor "
3497                          "\"%s\". This will be caused by one of the actor's "
3498                          "ancestors (%s) using the Cogl API directly to transform "
3499                          "children instead of using ::apply_transform().",
3500                          _clutter_actor_get_debug_name (self),
3501                          buf->str);
3502
3503               g_string_free (buf, TRUE);
3504             }
3505         }
3506 #endif /* CLUTTER_ENABLE_DEBUG */
3507
3508       cogl_set_modelview_matrix (&matrix);
3509     }
3510
3511   if (priv->has_clip)
3512     {
3513       cogl_clip_push_rectangle (priv->clip.x,
3514                                 priv->clip.y,
3515                                 priv->clip.x + priv->clip.width,
3516                                 priv->clip.y + priv->clip.height);
3517       clip_set = TRUE;
3518     }
3519   else if (priv->clip_to_allocation)
3520     {
3521       gfloat width, height;
3522
3523       width  = priv->allocation.x2 - priv->allocation.x1;
3524       height = priv->allocation.y2 - priv->allocation.y1;
3525
3526       cogl_clip_push_rectangle (0, 0, width, height);
3527       clip_set = TRUE;
3528     }
3529
3530   if (pick_mode == CLUTTER_PICK_NONE)
3531     {
3532       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3533
3534       /* We check whether we need to add the flatten effect before
3535          each paint so that we can avoid having a mechanism for
3536          applications to notify when the value of the
3537          has_overlaps virtual changes. */
3538       add_or_remove_flatten_effect (self);
3539     }
3540   else
3541     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3542
3543   /* We save the current paint volume so that the next time the
3544    * actor queues a redraw we can constrain the redraw to just
3545    * cover the union of the new bounding box and the old.
3546    *
3547    * We also fetch the current paint volume to perform culling so
3548    * we can avoid painting actors outside the current clip region.
3549    *
3550    * If we are painting inside a clone, we should neither update
3551    * the paint volume or use it to cull painting, since the paint
3552    * box represents the location of the source actor on the
3553    * screen.
3554    *
3555    * XXX: We are starting to do a lot of vertex transforms on
3556    * the CPU in a typical paint, so at some point we should
3557    * audit these and consider caching some things.
3558    *
3559    * NB: We don't perform culling while picking at this point because
3560    * clutter-stage.c doesn't setup the clipping planes appropriately.
3561    *
3562    * NB: We don't want to update the last-paint-volume during picking
3563    * because the last-paint-volume is used to determine the old screen
3564    * space location of an actor that has moved so we can know the
3565    * minimal region to redraw to clear an old view of the actor. If we
3566    * update this during picking then by the time we come around to
3567    * paint then the last-paint-volume would likely represent the new
3568    * actor position not the old.
3569    */
3570   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3571     {
3572       gboolean success;
3573       /* annoyingly gcc warns if uninitialized even though
3574        * the initialization is redundant :-( */
3575       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3576
3577       if (G_LIKELY ((clutter_paint_debug_flags &
3578                      (CLUTTER_DEBUG_DISABLE_CULLING |
3579                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3580                     (CLUTTER_DEBUG_DISABLE_CULLING |
3581                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3582         _clutter_actor_update_last_paint_volume (self);
3583
3584       success = cull_actor (self, &result);
3585
3586       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3587         _clutter_actor_paint_cull_result (self, success, result);
3588       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3589         goto done;
3590     }
3591
3592   if (priv->effects == NULL)
3593     {
3594       if (pick_mode == CLUTTER_PICK_NONE &&
3595           actor_has_shader_data (self))
3596         {
3597           _clutter_actor_shader_pre_paint (self, FALSE);
3598           shader_applied = TRUE;
3599         }
3600
3601       priv->next_effect_to_paint = NULL;
3602     }
3603   else
3604     priv->next_effect_to_paint =
3605       _clutter_meta_group_peek_metas (priv->effects);
3606
3607   clutter_actor_continue_paint (self);
3608
3609   if (shader_applied)
3610     _clutter_actor_shader_post_paint (self);
3611
3612   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3613                   pick_mode == CLUTTER_PICK_NONE))
3614     _clutter_actor_draw_paint_volume (self);
3615
3616 done:
3617   /* If we make it here then the actor has run through a complete
3618      paint run including all the effects so it's no longer dirty */
3619   if (pick_mode == CLUTTER_PICK_NONE)
3620     priv->is_dirty = FALSE;
3621
3622   if (clip_set)
3623     cogl_clip_pop();
3624
3625   cogl_pop_matrix();
3626
3627   /* paint sequence complete */
3628   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3629 }
3630
3631 /**
3632  * clutter_actor_continue_paint:
3633  * @self: A #ClutterActor
3634  *
3635  * Run the next stage of the paint sequence. This function should only
3636  * be called within the implementation of the ‘run’ virtual of a
3637  * #ClutterEffect. It will cause the run method of the next effect to
3638  * be applied, or it will paint the actual actor if the current effect
3639  * is the last effect in the chain.
3640  *
3641  * Since: 1.8
3642  */
3643 void
3644 clutter_actor_continue_paint (ClutterActor *self)
3645 {
3646   ClutterActorPrivate *priv;
3647
3648   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3649   /* This should only be called from with in the ‘run’ implementation
3650      of a ClutterEffect */
3651   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3652
3653   priv = self->priv;
3654
3655   /* Skip any effects that are disabled */
3656   while (priv->next_effect_to_paint &&
3657          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3658     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3659
3660   /* If this has come from the last effect then we'll just paint the
3661      actual actor */
3662   if (priv->next_effect_to_paint == NULL)
3663     {
3664       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3665         {
3666           ClutterPaintNode *dummy;
3667
3668           /* XXX - this will go away in 2.0, when we can get rid of this
3669            * stuff and switch to a pure retained render tree of PaintNodes
3670            * for the entire frame, starting from the Stage; the paint()
3671            * virtual function can then be called directly.
3672            */
3673           dummy = _clutter_dummy_node_new (self);
3674           clutter_paint_node_set_name (dummy, "Root");
3675
3676           /* XXX - for 1.12, we use the return value of paint_node() to
3677            * decide whether we should emit the ::paint signal.
3678            */
3679           clutter_actor_paint_node (self, dummy);
3680           clutter_paint_node_unref (dummy);
3681
3682           g_signal_emit (self, actor_signals[PAINT], 0);
3683         }
3684       else
3685         {
3686           ClutterColor col = { 0, };
3687
3688           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3689
3690           /* Actor will then paint silhouette of itself in supplied
3691            * color.  See clutter_stage_get_actor_at_pos() for where
3692            * picking is enabled.
3693            */
3694           g_signal_emit (self, actor_signals[PICK], 0, &col);
3695         }
3696     }
3697   else
3698     {
3699       ClutterEffect *old_current_effect;
3700       ClutterEffectPaintFlags run_flags = 0;
3701
3702       /* Cache the current effect so that we can put it back before
3703          returning */
3704       old_current_effect = priv->current_effect;
3705
3706       priv->current_effect = priv->next_effect_to_paint->data;
3707       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3708
3709       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3710         {
3711           if (priv->is_dirty)
3712             {
3713               /* If there's an effect queued with this redraw then all
3714                  effects up to that one will be considered dirty. It
3715                  is expected the queued effect will paint the cached
3716                  image and not call clutter_actor_continue_paint again
3717                  (although it should work ok if it does) */
3718               if (priv->effect_to_redraw == NULL ||
3719                   priv->current_effect != priv->effect_to_redraw)
3720                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3721             }
3722
3723           _clutter_effect_paint (priv->current_effect, run_flags);
3724         }
3725       else
3726         {
3727           /* We can't determine when an actor has been modified since
3728              its last pick so lets just assume it has always been
3729              modified */
3730           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3731
3732           _clutter_effect_pick (priv->current_effect, run_flags);
3733         }
3734
3735       priv->current_effect = old_current_effect;
3736     }
3737 }
3738
3739 static ClutterActorTraverseVisitFlags
3740 invalidate_queue_redraw_entry (ClutterActor *self,
3741                                int           depth,
3742                                gpointer      user_data)
3743 {
3744   ClutterActorPrivate *priv = self->priv;
3745
3746   if (priv->queue_redraw_entry != NULL)
3747     {
3748       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3749       priv->queue_redraw_entry = NULL;
3750     }
3751
3752   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3753 }
3754
3755 static inline void
3756 remove_child (ClutterActor *self,
3757               ClutterActor *child)
3758 {
3759   ClutterActor *prev_sibling, *next_sibling;
3760
3761   prev_sibling = child->priv->prev_sibling;
3762   next_sibling = child->priv->next_sibling;
3763
3764   if (prev_sibling != NULL)
3765     prev_sibling->priv->next_sibling = next_sibling;
3766
3767   if (next_sibling != NULL)
3768     next_sibling->priv->prev_sibling = prev_sibling;
3769
3770   if (self->priv->first_child == child)
3771     self->priv->first_child = next_sibling;
3772
3773   if (self->priv->last_child == child)
3774     self->priv->last_child = prev_sibling;
3775
3776   child->priv->parent = NULL;
3777   child->priv->prev_sibling = NULL;
3778   child->priv->next_sibling = NULL;
3779 }
3780
3781 typedef enum {
3782   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3783   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3784   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3785   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3786   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3787   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3788
3789   /* default flags for public API */
3790   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3791                                     REMOVE_CHILD_EMIT_PARENT_SET |
3792                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3793                                     REMOVE_CHILD_CHECK_STATE |
3794                                     REMOVE_CHILD_FLUSH_QUEUE |
3795                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3796
3797   /* flags for legacy/deprecated API */
3798   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3799                                     REMOVE_CHILD_FLUSH_QUEUE |
3800                                     REMOVE_CHILD_EMIT_PARENT_SET |
3801                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3802 } ClutterActorRemoveChildFlags;
3803
3804 /*< private >
3805  * clutter_actor_remove_child_internal:
3806  * @self: a #ClutterActor
3807  * @child: the child of @self that has to be removed
3808  * @flags: control the removal operations
3809  *
3810  * Removes @child from the list of children of @self.
3811  */
3812 static void
3813 clutter_actor_remove_child_internal (ClutterActor                 *self,
3814                                      ClutterActor                 *child,
3815                                      ClutterActorRemoveChildFlags  flags)
3816 {
3817   ClutterActor *old_first, *old_last;
3818   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3819   gboolean flush_queue;
3820   gboolean notify_first_last;
3821   gboolean was_mapped;
3822
3823   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3824   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3825   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3826   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3827   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3828   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3829
3830   g_object_freeze_notify (G_OBJECT (self));
3831
3832   if (destroy_meta)
3833     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3834
3835   if (check_state)
3836     {
3837       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3838
3839       /* we need to unrealize *before* we set parent_actor to NULL,
3840        * because in an unrealize method actors are dissociating from the
3841        * stage, which means they need to be able to
3842        * clutter_actor_get_stage().
3843        *
3844        * yhis should unmap and unrealize, unless we're reparenting.
3845        */
3846       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3847     }
3848   else
3849     was_mapped = FALSE;
3850
3851   if (flush_queue)
3852     {
3853       /* We take this opportunity to invalidate any queue redraw entry
3854        * associated with the actor and descendants since we won't be able to
3855        * determine the appropriate stage after this.
3856        *
3857        * we do this after we updated the mapped state because actors might
3858        * end up queueing redraws inside their mapped/unmapped virtual
3859        * functions, and if we invalidate the redraw entry we could end up
3860        * with an inconsistent state and weird memory corruption. see
3861        * bugs:
3862        *
3863        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3864        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3865        */
3866       _clutter_actor_traverse (child,
3867                                0,
3868                                invalidate_queue_redraw_entry,
3869                                NULL,
3870                                NULL);
3871     }
3872
3873   old_first = self->priv->first_child;
3874   old_last = self->priv->last_child;
3875
3876   remove_child (self, child);
3877
3878   self->priv->n_children -= 1;
3879
3880   self->priv->age += 1;
3881
3882   /* clutter_actor_reparent() will emit ::parent-set for us */
3883   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3884     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3885
3886   /* if the child was mapped then we need to relayout ourselves to account
3887    * for the removed child
3888    */
3889   if (was_mapped)
3890     clutter_actor_queue_relayout (self);
3891
3892   /* we need to emit the signal before dropping the reference */
3893   if (emit_actor_removed)
3894     g_signal_emit_by_name (self, "actor-removed", child);
3895
3896   if (notify_first_last)
3897     {
3898       if (old_first != self->priv->first_child)
3899         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3900
3901       if (old_last != self->priv->last_child)
3902         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3903     }
3904
3905   g_object_thaw_notify (G_OBJECT (self));
3906
3907   /* remove the reference we acquired in clutter_actor_add_child() */
3908   g_object_unref (child);
3909 }
3910
3911 static const ClutterTransformInfo default_transform_info = {
3912   0.0, { 0, },          /* rotation-x */
3913   0.0, { 0, },          /* rotation-y */
3914   0.0, { 0, },          /* rotation-z */
3915
3916   1.0, 1.0, { 0, },     /* scale */
3917
3918   { 0, },               /* anchor */
3919
3920   0.0,                  /* depth */
3921 };
3922
3923 /*< private >
3924  * _clutter_actor_get_transform_info_or_defaults:
3925  * @self: a #ClutterActor
3926  *
3927  * Retrieves the ClutterTransformInfo structure associated to an actor.
3928  *
3929  * If the actor does not have a ClutterTransformInfo structure associated
3930  * to it, then the default structure will be returned.
3931  *
3932  * This function should only be used for getters.
3933  *
3934  * Return value: a const pointer to the ClutterTransformInfo structure
3935  */
3936 const ClutterTransformInfo *
3937 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3938 {
3939   ClutterTransformInfo *info;
3940
3941   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3942   if (info != NULL)
3943     return info;
3944
3945   return &default_transform_info;
3946 }
3947
3948 static void
3949 clutter_transform_info_free (gpointer data)
3950 {
3951   if (data != NULL)
3952     g_slice_free (ClutterTransformInfo, data);
3953 }
3954
3955 /*< private >
3956  * _clutter_actor_get_transform_info:
3957  * @self: a #ClutterActor
3958  *
3959  * Retrieves a pointer to the ClutterTransformInfo structure.
3960  *
3961  * If the actor does not have a ClutterTransformInfo associated to it, one
3962  * will be created and initialized to the default values.
3963  *
3964  * This function should be used for setters.
3965  *
3966  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3967  * instead.
3968  *
3969  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3970  *   structure
3971  */
3972 ClutterTransformInfo *
3973 _clutter_actor_get_transform_info (ClutterActor *self)
3974 {
3975   ClutterTransformInfo *info;
3976
3977   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3978   if (info == NULL)
3979     {
3980       info = g_slice_new (ClutterTransformInfo);
3981
3982       *info = default_transform_info;
3983
3984       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3985                                info,
3986                                clutter_transform_info_free);
3987     }
3988
3989   return info;
3990 }
3991
3992 /*< private >
3993  * clutter_actor_set_rotation_angle_internal:
3994  * @self: a #ClutterActor
3995  * @axis: the axis of the angle to change
3996  * @angle: the angle of rotation
3997  *
3998  * Sets the rotation angle on the given axis without affecting the
3999  * rotation center point.
4000  */
4001 static inline void
4002 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
4003                                            ClutterRotateAxis  axis,
4004                                            gdouble            angle)
4005 {
4006   GObject *obj = G_OBJECT (self);
4007   ClutterTransformInfo *info;
4008
4009   info = _clutter_actor_get_transform_info (self);
4010
4011   g_object_freeze_notify (obj);
4012
4013   switch (axis)
4014     {
4015     case CLUTTER_X_AXIS:
4016       info->rx_angle = angle;
4017       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4018       break;
4019
4020     case CLUTTER_Y_AXIS:
4021       info->ry_angle = angle;
4022       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4023       break;
4024
4025     case CLUTTER_Z_AXIS:
4026       info->rz_angle = angle;
4027       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4028       break;
4029     }
4030
4031   self->priv->transform_valid = FALSE;
4032
4033   g_object_thaw_notify (obj);
4034
4035   clutter_actor_queue_redraw (self);
4036 }
4037
4038 static inline void
4039 clutter_actor_set_rotation_angle (ClutterActor      *self,
4040                                   ClutterRotateAxis  axis,
4041                                   gdouble            angle)
4042 {
4043   const ClutterTransformInfo *info;
4044   const double *cur_angle_p = NULL;
4045   GParamSpec *pspec = NULL;
4046
4047   info = _clutter_actor_get_transform_info_or_defaults (self);
4048
4049   switch (axis)
4050     {
4051     case CLUTTER_X_AXIS:
4052       cur_angle_p = &info->rx_angle;
4053       pspec = obj_props[PROP_ROTATION_ANGLE_X];
4054       break;
4055
4056     case CLUTTER_Y_AXIS:
4057       cur_angle_p = &info->ry_angle;
4058       pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4059       break;
4060
4061     case CLUTTER_Z_AXIS:
4062       cur_angle_p = &info->rz_angle;
4063       pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4064       break;
4065     }
4066
4067   g_assert (pspec != NULL);
4068   g_assert (cur_angle_p != NULL);
4069
4070   if (_clutter_actor_get_transition (self, pspec) == NULL)
4071     _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4072   else
4073     _clutter_actor_update_transition (self, pspec, angle);
4074
4075   clutter_actor_queue_redraw (self);
4076 }
4077
4078 /*< private >
4079  * clutter_actor_set_rotation_center_internal:
4080  * @self: a #ClutterActor
4081  * @axis: the axis of the center to change
4082  * @center: the coordinates of the rotation center
4083  *
4084  * Sets the rotation center on the given axis without affecting the
4085  * rotation angle.
4086  */
4087 static inline void
4088 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4089                                             ClutterRotateAxis    axis,
4090                                             const ClutterVertex *center)
4091 {
4092   GObject *obj = G_OBJECT (self);
4093   ClutterTransformInfo *info;
4094   ClutterVertex v = { 0, 0, 0 };
4095
4096   info = _clutter_actor_get_transform_info (self);
4097
4098   if (center != NULL)
4099     v = *center;
4100
4101   g_object_freeze_notify (obj);
4102
4103   switch (axis)
4104     {
4105     case CLUTTER_X_AXIS:
4106       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4107       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4108       break;
4109
4110     case CLUTTER_Y_AXIS:
4111       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4112       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4113       break;
4114
4115     case CLUTTER_Z_AXIS:
4116       /* if the previously set rotation center was fractional, then
4117        * setting explicit coordinates will have to notify the
4118        * :rotation-center-z-gravity property as well
4119        */
4120       if (info->rz_center.is_fractional)
4121         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4122
4123       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4124       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4125       break;
4126     }
4127
4128   self->priv->transform_valid = FALSE;
4129
4130   g_object_thaw_notify (obj);
4131
4132   clutter_actor_queue_redraw (self);
4133 }
4134
4135 static void
4136 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4137                                          double factor,
4138                                          GParamSpec *pspec)
4139 {
4140   GObject *obj = G_OBJECT (self);
4141   ClutterTransformInfo *info;
4142
4143   info = _clutter_actor_get_transform_info (self);
4144
4145   if (pspec == obj_props[PROP_SCALE_X])
4146     info->scale_x = factor;
4147   else
4148     info->scale_y = factor;
4149
4150   self->priv->transform_valid = FALSE;
4151   clutter_actor_queue_redraw (self);
4152   g_object_notify_by_pspec (obj, pspec);
4153 }
4154
4155 static inline void
4156 clutter_actor_set_scale_factor (ClutterActor      *self,
4157                                 ClutterRotateAxis  axis,
4158                                 gdouble            factor)
4159 {
4160   const ClutterTransformInfo *info;
4161   const double *scale_p = NULL;
4162   GParamSpec *pspec = NULL;
4163
4164   info = _clutter_actor_get_transform_info_or_defaults (self);
4165
4166   switch (axis)
4167     {
4168     case CLUTTER_X_AXIS:
4169       pspec = obj_props[PROP_SCALE_X];
4170       scale_p = &info->scale_x;
4171       break;
4172
4173     case CLUTTER_Y_AXIS:
4174       pspec = obj_props[PROP_SCALE_Y];
4175       scale_p = &info->scale_y;
4176       break;
4177
4178     case CLUTTER_Z_AXIS:
4179       break;
4180     }
4181
4182   g_assert (pspec != NULL);
4183   g_assert (scale_p != NULL);
4184
4185   if (_clutter_actor_get_transition (self, pspec) == NULL)
4186     _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4187   else
4188     _clutter_actor_update_transition (self, pspec, factor);
4189
4190   clutter_actor_queue_redraw (self);
4191 }
4192
4193 static inline void
4194 clutter_actor_set_scale_center (ClutterActor      *self,
4195                                 ClutterRotateAxis  axis,
4196                                 gfloat             coord)
4197 {
4198   GObject *obj = G_OBJECT (self);
4199   ClutterTransformInfo *info;
4200   gfloat center_x, center_y;
4201
4202   info = _clutter_actor_get_transform_info (self);
4203
4204   g_object_freeze_notify (obj);
4205
4206   /* get the current scale center coordinates */
4207   clutter_anchor_coord_get_units (self, &info->scale_center,
4208                                   &center_x,
4209                                   &center_y,
4210                                   NULL);
4211
4212   /* we need to notify this too, because setting explicit coordinates will
4213    * change the gravity as a side effect
4214    */
4215   if (info->scale_center.is_fractional)
4216     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4217
4218   switch (axis)
4219     {
4220     case CLUTTER_X_AXIS:
4221       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4222       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4223       break;
4224
4225     case CLUTTER_Y_AXIS:
4226       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4227       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4228       break;
4229
4230     default:
4231       g_assert_not_reached ();
4232     }
4233
4234   self->priv->transform_valid = FALSE;
4235
4236   clutter_actor_queue_redraw (self);
4237
4238   g_object_thaw_notify (obj);
4239 }
4240
4241 static inline void
4242 clutter_actor_set_scale_gravity (ClutterActor   *self,
4243                                  ClutterGravity  gravity)
4244 {
4245   ClutterTransformInfo *info;
4246   GObject *obj;
4247
4248   info = _clutter_actor_get_transform_info (self);
4249   obj = G_OBJECT (self);
4250
4251   if (gravity == CLUTTER_GRAVITY_NONE)
4252     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4253   else
4254     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4255
4256   self->priv->transform_valid = FALSE;
4257
4258   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4259   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4260   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4261
4262   clutter_actor_queue_redraw (self);
4263 }
4264
4265 static inline void
4266 clutter_actor_set_anchor_coord (ClutterActor      *self,
4267                                 ClutterRotateAxis  axis,
4268                                 gfloat             coord)
4269 {
4270   GObject *obj = G_OBJECT (self);
4271   ClutterTransformInfo *info;
4272   gfloat anchor_x, anchor_y;
4273
4274   info = _clutter_actor_get_transform_info (self);
4275
4276   g_object_freeze_notify (obj);
4277
4278   clutter_anchor_coord_get_units (self, &info->anchor,
4279                                   &anchor_x,
4280                                   &anchor_y,
4281                                   NULL);
4282
4283   if (info->anchor.is_fractional)
4284     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4285
4286   switch (axis)
4287     {
4288     case CLUTTER_X_AXIS:
4289       clutter_anchor_coord_set_units (&info->anchor,
4290                                       coord,
4291                                       anchor_y,
4292                                       0.0);
4293       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4294       break;
4295
4296     case CLUTTER_Y_AXIS:
4297       clutter_anchor_coord_set_units (&info->anchor,
4298                                       anchor_x,
4299                                       coord,
4300                                       0.0);
4301       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4302       break;
4303
4304     default:
4305       g_assert_not_reached ();
4306     }
4307
4308   self->priv->transform_valid = FALSE;
4309
4310   clutter_actor_queue_redraw (self);
4311
4312   g_object_thaw_notify (obj);
4313 }
4314
4315 static void
4316 clutter_actor_set_property (GObject      *object,
4317                             guint         prop_id,
4318                             const GValue *value,
4319                             GParamSpec   *pspec)
4320 {
4321   ClutterActor *actor = CLUTTER_ACTOR (object);
4322   ClutterActorPrivate *priv = actor->priv;
4323
4324   switch (prop_id)
4325     {
4326     case PROP_X:
4327       clutter_actor_set_x (actor, g_value_get_float (value));
4328       break;
4329
4330     case PROP_Y:
4331       clutter_actor_set_y (actor, g_value_get_float (value));
4332       break;
4333
4334     case PROP_WIDTH:
4335       clutter_actor_set_width (actor, g_value_get_float (value));
4336       break;
4337
4338     case PROP_HEIGHT:
4339       clutter_actor_set_height (actor, g_value_get_float (value));
4340       break;
4341
4342     case PROP_FIXED_X:
4343       clutter_actor_set_x (actor, g_value_get_float (value));
4344       break;
4345
4346     case PROP_FIXED_Y:
4347       clutter_actor_set_y (actor, g_value_get_float (value));
4348       break;
4349
4350     case PROP_FIXED_POSITION_SET:
4351       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4352       break;
4353
4354     case PROP_MIN_WIDTH:
4355       clutter_actor_set_min_width (actor, g_value_get_float (value));
4356       break;
4357
4358     case PROP_MIN_HEIGHT:
4359       clutter_actor_set_min_height (actor, g_value_get_float (value));
4360       break;
4361
4362     case PROP_NATURAL_WIDTH:
4363       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4364       break;
4365
4366     case PROP_NATURAL_HEIGHT:
4367       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4368       break;
4369
4370     case PROP_MIN_WIDTH_SET:
4371       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4372       break;
4373
4374     case PROP_MIN_HEIGHT_SET:
4375       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4376       break;
4377
4378     case PROP_NATURAL_WIDTH_SET:
4379       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4380       break;
4381
4382     case PROP_NATURAL_HEIGHT_SET:
4383       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4384       break;
4385
4386     case PROP_REQUEST_MODE:
4387       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4388       break;
4389
4390     case PROP_DEPTH:
4391       clutter_actor_set_depth (actor, g_value_get_float (value));
4392       break;
4393
4394     case PROP_OPACITY:
4395       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4396       break;
4397
4398     case PROP_OFFSCREEN_REDIRECT:
4399       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4400       break;
4401
4402     case PROP_NAME:
4403       clutter_actor_set_name (actor, g_value_get_string (value));
4404       break;
4405
4406     case PROP_VISIBLE:
4407       if (g_value_get_boolean (value) == TRUE)
4408         clutter_actor_show (actor);
4409       else
4410         clutter_actor_hide (actor);
4411       break;
4412
4413     case PROP_SCALE_X:
4414       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4415                                       g_value_get_double (value));
4416       break;
4417
4418     case PROP_SCALE_Y:
4419       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4420                                       g_value_get_double (value));
4421       break;
4422
4423     case PROP_SCALE_CENTER_X:
4424       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4425                                       g_value_get_float (value));
4426       break;
4427
4428     case PROP_SCALE_CENTER_Y:
4429       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4430                                       g_value_get_float (value));
4431       break;
4432
4433     case PROP_SCALE_GRAVITY:
4434       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4435       break;
4436
4437     case PROP_CLIP:
4438       {
4439         const ClutterGeometry *geom = g_value_get_boxed (value);
4440
4441         clutter_actor_set_clip (actor,
4442                                 geom->x, geom->y,
4443                                 geom->width, geom->height);
4444       }
4445       break;
4446
4447     case PROP_CLIP_TO_ALLOCATION:
4448       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4449       break;
4450
4451     case PROP_REACTIVE:
4452       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4453       break;
4454
4455     case PROP_ROTATION_ANGLE_X:
4456       clutter_actor_set_rotation_angle (actor,
4457                                         CLUTTER_X_AXIS,
4458                                         g_value_get_double (value));
4459       break;
4460
4461     case PROP_ROTATION_ANGLE_Y:
4462       clutter_actor_set_rotation_angle (actor,
4463                                         CLUTTER_Y_AXIS,
4464                                         g_value_get_double (value));
4465       break;
4466
4467     case PROP_ROTATION_ANGLE_Z:
4468       clutter_actor_set_rotation_angle (actor,
4469                                         CLUTTER_Z_AXIS,
4470                                         g_value_get_double (value));
4471       break;
4472
4473     case PROP_ROTATION_CENTER_X:
4474       clutter_actor_set_rotation_center_internal (actor,
4475                                                   CLUTTER_X_AXIS,
4476                                                   g_value_get_boxed (value));
4477       break;
4478
4479     case PROP_ROTATION_CENTER_Y:
4480       clutter_actor_set_rotation_center_internal (actor,
4481                                                   CLUTTER_Y_AXIS,
4482                                                   g_value_get_boxed (value));
4483       break;
4484
4485     case PROP_ROTATION_CENTER_Z:
4486       clutter_actor_set_rotation_center_internal (actor,
4487                                                   CLUTTER_Z_AXIS,
4488                                                   g_value_get_boxed (value));
4489       break;
4490
4491     case PROP_ROTATION_CENTER_Z_GRAVITY:
4492       {
4493         const ClutterTransformInfo *info;
4494
4495         info = _clutter_actor_get_transform_info_or_defaults (actor);
4496         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4497                                                    g_value_get_enum (value));
4498       }
4499       break;
4500
4501     case PROP_ANCHOR_X:
4502       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4503                                       g_value_get_float (value));
4504       break;
4505
4506     case PROP_ANCHOR_Y:
4507       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4508                                       g_value_get_float (value));
4509       break;
4510
4511     case PROP_ANCHOR_GRAVITY:
4512       clutter_actor_set_anchor_point_from_gravity (actor,
4513                                                    g_value_get_enum (value));
4514       break;
4515
4516     case PROP_SHOW_ON_SET_PARENT:
4517       priv->show_on_set_parent = g_value_get_boolean (value);
4518       break;
4519
4520     case PROP_TEXT_DIRECTION:
4521       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4522       break;
4523
4524     case PROP_ACTIONS:
4525       clutter_actor_add_action (actor, g_value_get_object (value));
4526       break;
4527
4528     case PROP_CONSTRAINTS:
4529       clutter_actor_add_constraint (actor, g_value_get_object (value));
4530       break;
4531
4532     case PROP_EFFECT:
4533       clutter_actor_add_effect (actor, g_value_get_object (value));
4534       break;
4535
4536     case PROP_LAYOUT_MANAGER:
4537       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4538       break;
4539
4540     case PROP_X_ALIGN:
4541       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4542       break;
4543
4544     case PROP_Y_ALIGN:
4545       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4546       break;
4547
4548     case PROP_MARGIN_TOP:
4549       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4550       break;
4551
4552     case PROP_MARGIN_BOTTOM:
4553       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4554       break;
4555
4556     case PROP_MARGIN_LEFT:
4557       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4558       break;
4559
4560     case PROP_MARGIN_RIGHT:
4561       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4562       break;
4563
4564     case PROP_BACKGROUND_COLOR:
4565       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4566       break;
4567
4568     case PROP_CONTENT:
4569       clutter_actor_set_content (actor, g_value_get_object (value));
4570       break;
4571
4572     case PROP_CONTENT_GRAVITY:
4573       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4574       break;
4575
4576     case PROP_MINIFICATION_FILTER:
4577       clutter_actor_set_content_scaling_filters (actor,
4578                                                  g_value_get_enum (value),
4579                                                  actor->priv->mag_filter);
4580       break;
4581
4582     case PROP_MAGNIFICATION_FILTER:
4583       clutter_actor_set_content_scaling_filters (actor,
4584                                                  actor->priv->min_filter,
4585                                                  g_value_get_enum (value));
4586       break;
4587
4588     default:
4589       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4590       break;
4591     }
4592 }
4593
4594 static void
4595 clutter_actor_get_property (GObject    *object,
4596                             guint       prop_id,
4597                             GValue     *value,
4598                             GParamSpec *pspec)
4599 {
4600   ClutterActor *actor = CLUTTER_ACTOR (object);
4601   ClutterActorPrivate *priv = actor->priv;
4602
4603   switch (prop_id)
4604     {
4605     case PROP_X:
4606       g_value_set_float (value, clutter_actor_get_x (actor));
4607       break;
4608
4609     case PROP_Y:
4610       g_value_set_float (value, clutter_actor_get_y (actor));
4611       break;
4612
4613     case PROP_WIDTH:
4614       g_value_set_float (value, clutter_actor_get_width (actor));
4615       break;
4616
4617     case PROP_HEIGHT:
4618       g_value_set_float (value, clutter_actor_get_height (actor));
4619       break;
4620
4621     case PROP_FIXED_X:
4622       {
4623         const ClutterLayoutInfo *info;
4624
4625         info = _clutter_actor_get_layout_info_or_defaults (actor);
4626         g_value_set_float (value, info->fixed_x);
4627       }
4628       break;
4629
4630     case PROP_FIXED_Y:
4631       {
4632         const ClutterLayoutInfo *info;
4633
4634         info = _clutter_actor_get_layout_info_or_defaults (actor);
4635         g_value_set_float (value, info->fixed_y);
4636       }
4637       break;
4638
4639     case PROP_FIXED_POSITION_SET:
4640       g_value_set_boolean (value, priv->position_set);
4641       break;
4642
4643     case PROP_MIN_WIDTH:
4644       {
4645         const ClutterLayoutInfo *info;
4646
4647         info = _clutter_actor_get_layout_info_or_defaults (actor);
4648         g_value_set_float (value, info->min_width);
4649       }
4650       break;
4651
4652     case PROP_MIN_HEIGHT:
4653       {
4654         const ClutterLayoutInfo *info;
4655
4656         info = _clutter_actor_get_layout_info_or_defaults (actor);
4657         g_value_set_float (value, info->min_height);
4658       }
4659       break;
4660
4661     case PROP_NATURAL_WIDTH:
4662       {
4663         const ClutterLayoutInfo *info;
4664
4665         info = _clutter_actor_get_layout_info_or_defaults (actor);
4666         g_value_set_float (value, info->natural_width);
4667       }
4668       break;
4669
4670     case PROP_NATURAL_HEIGHT:
4671       {
4672         const ClutterLayoutInfo *info;
4673
4674         info = _clutter_actor_get_layout_info_or_defaults (actor);
4675         g_value_set_float (value, info->natural_height);
4676       }
4677       break;
4678
4679     case PROP_MIN_WIDTH_SET:
4680       g_value_set_boolean (value, priv->min_width_set);
4681       break;
4682
4683     case PROP_MIN_HEIGHT_SET:
4684       g_value_set_boolean (value, priv->min_height_set);
4685       break;
4686
4687     case PROP_NATURAL_WIDTH_SET:
4688       g_value_set_boolean (value, priv->natural_width_set);
4689       break;
4690
4691     case PROP_NATURAL_HEIGHT_SET:
4692       g_value_set_boolean (value, priv->natural_height_set);
4693       break;
4694
4695     case PROP_REQUEST_MODE:
4696       g_value_set_enum (value, priv->request_mode);
4697       break;
4698
4699     case PROP_ALLOCATION:
4700       g_value_set_boxed (value, &priv->allocation);
4701       break;
4702
4703     case PROP_DEPTH:
4704       g_value_set_float (value, clutter_actor_get_depth (actor));
4705       break;
4706
4707     case PROP_OPACITY:
4708       g_value_set_uint (value, priv->opacity);
4709       break;
4710
4711     case PROP_OFFSCREEN_REDIRECT:
4712       g_value_set_enum (value, priv->offscreen_redirect);
4713       break;
4714
4715     case PROP_NAME:
4716       g_value_set_string (value, priv->name);
4717       break;
4718
4719     case PROP_VISIBLE:
4720       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4721       break;
4722
4723     case PROP_MAPPED:
4724       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4725       break;
4726
4727     case PROP_REALIZED:
4728       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4729       break;
4730
4731     case PROP_HAS_CLIP:
4732       g_value_set_boolean (value, priv->has_clip);
4733       break;
4734
4735     case PROP_CLIP:
4736       {
4737         ClutterGeometry clip;
4738
4739         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4740         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4741         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4742         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4743
4744         g_value_set_boxed (value, &clip);
4745       }
4746       break;
4747
4748     case PROP_CLIP_TO_ALLOCATION:
4749       g_value_set_boolean (value, priv->clip_to_allocation);
4750       break;
4751
4752     case PROP_SCALE_X:
4753       {
4754         const ClutterTransformInfo *info;
4755
4756         info = _clutter_actor_get_transform_info_or_defaults (actor);
4757         g_value_set_double (value, info->scale_x);
4758       }
4759       break;
4760
4761     case PROP_SCALE_Y:
4762       {
4763         const ClutterTransformInfo *info;
4764
4765         info = _clutter_actor_get_transform_info_or_defaults (actor);
4766         g_value_set_double (value, info->scale_y);
4767       }
4768       break;
4769
4770     case PROP_SCALE_CENTER_X:
4771       {
4772         gfloat center;
4773
4774         clutter_actor_get_scale_center (actor, &center, NULL);
4775
4776         g_value_set_float (value, center);
4777       }
4778       break;
4779
4780     case PROP_SCALE_CENTER_Y:
4781       {
4782         gfloat center;
4783
4784         clutter_actor_get_scale_center (actor, NULL, &center);
4785
4786         g_value_set_float (value, center);
4787       }
4788       break;
4789
4790     case PROP_SCALE_GRAVITY:
4791       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4792       break;
4793
4794     case PROP_REACTIVE:
4795       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4796       break;
4797
4798     case PROP_ROTATION_ANGLE_X:
4799       {
4800         const ClutterTransformInfo *info;
4801
4802         info = _clutter_actor_get_transform_info_or_defaults (actor);
4803         g_value_set_double (value, info->rx_angle);
4804       }
4805       break;
4806
4807     case PROP_ROTATION_ANGLE_Y:
4808       {
4809         const ClutterTransformInfo *info;
4810
4811         info = _clutter_actor_get_transform_info_or_defaults (actor);
4812         g_value_set_double (value, info->ry_angle);
4813       }
4814       break;
4815
4816     case PROP_ROTATION_ANGLE_Z:
4817       {
4818         const ClutterTransformInfo *info;
4819
4820         info = _clutter_actor_get_transform_info_or_defaults (actor);
4821         g_value_set_double (value, info->rz_angle);
4822       }
4823       break;
4824
4825     case PROP_ROTATION_CENTER_X:
4826       {
4827         ClutterVertex center;
4828
4829         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4830                                     &center.x,
4831                                     &center.y,
4832                                     &center.z);
4833
4834         g_value_set_boxed (value, &center);
4835       }
4836       break;
4837
4838     case PROP_ROTATION_CENTER_Y:
4839       {
4840         ClutterVertex center;
4841
4842         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4843                                     &center.x,
4844                                     &center.y,
4845                                     &center.z);
4846
4847         g_value_set_boxed (value, &center);
4848       }
4849       break;
4850
4851     case PROP_ROTATION_CENTER_Z:
4852       {
4853         ClutterVertex center;
4854
4855         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4856                                     &center.x,
4857                                     &center.y,
4858                                     &center.z);
4859
4860         g_value_set_boxed (value, &center);
4861       }
4862       break;
4863
4864     case PROP_ROTATION_CENTER_Z_GRAVITY:
4865       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4866       break;
4867
4868     case PROP_ANCHOR_X:
4869       {
4870         const ClutterTransformInfo *info;
4871         gfloat anchor_x;
4872
4873         info = _clutter_actor_get_transform_info_or_defaults (actor);
4874         clutter_anchor_coord_get_units (actor, &info->anchor,
4875                                         &anchor_x,
4876                                         NULL,
4877                                         NULL);
4878         g_value_set_float (value, anchor_x);
4879       }
4880       break;
4881
4882     case PROP_ANCHOR_Y:
4883       {
4884         const ClutterTransformInfo *info;
4885         gfloat anchor_y;
4886
4887         info = _clutter_actor_get_transform_info_or_defaults (actor);
4888         clutter_anchor_coord_get_units (actor, &info->anchor,
4889                                         NULL,
4890                                         &anchor_y,
4891                                         NULL);
4892         g_value_set_float (value, anchor_y);
4893       }
4894       break;
4895
4896     case PROP_ANCHOR_GRAVITY:
4897       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4898       break;
4899
4900     case PROP_SHOW_ON_SET_PARENT:
4901       g_value_set_boolean (value, priv->show_on_set_parent);
4902       break;
4903
4904     case PROP_TEXT_DIRECTION:
4905       g_value_set_enum (value, priv->text_direction);
4906       break;
4907
4908     case PROP_HAS_POINTER:
4909       g_value_set_boolean (value, priv->has_pointer);
4910       break;
4911
4912     case PROP_LAYOUT_MANAGER:
4913       g_value_set_object (value, priv->layout_manager);
4914       break;
4915
4916     case PROP_X_ALIGN:
4917       {
4918         const ClutterLayoutInfo *info;
4919
4920         info = _clutter_actor_get_layout_info_or_defaults (actor);
4921         g_value_set_enum (value, info->x_align);
4922       }
4923       break;
4924
4925     case PROP_Y_ALIGN:
4926       {
4927         const ClutterLayoutInfo *info;
4928
4929         info = _clutter_actor_get_layout_info_or_defaults (actor);
4930         g_value_set_enum (value, info->y_align);
4931       }
4932       break;
4933
4934     case PROP_MARGIN_TOP:
4935       {
4936         const ClutterLayoutInfo *info;
4937
4938         info = _clutter_actor_get_layout_info_or_defaults (actor);
4939         g_value_set_float (value, info->margin.top);
4940       }
4941       break;
4942
4943     case PROP_MARGIN_BOTTOM:
4944       {
4945         const ClutterLayoutInfo *info;
4946
4947         info = _clutter_actor_get_layout_info_or_defaults (actor);
4948         g_value_set_float (value, info->margin.bottom);
4949       }
4950       break;
4951
4952     case PROP_MARGIN_LEFT:
4953       {
4954         const ClutterLayoutInfo *info;
4955
4956         info = _clutter_actor_get_layout_info_or_defaults (actor);
4957         g_value_set_float (value, info->margin.left);
4958       }
4959       break;
4960
4961     case PROP_MARGIN_RIGHT:
4962       {
4963         const ClutterLayoutInfo *info;
4964
4965         info = _clutter_actor_get_layout_info_or_defaults (actor);
4966         g_value_set_float (value, info->margin.right);
4967       }
4968       break;
4969
4970     case PROP_BACKGROUND_COLOR_SET:
4971       g_value_set_boolean (value, priv->bg_color_set);
4972       break;
4973
4974     case PROP_BACKGROUND_COLOR:
4975       g_value_set_boxed (value, &priv->bg_color);
4976       break;
4977
4978     case PROP_FIRST_CHILD:
4979       g_value_set_object (value, priv->first_child);
4980       break;
4981
4982     case PROP_LAST_CHILD:
4983       g_value_set_object (value, priv->last_child);
4984       break;
4985
4986     case PROP_CONTENT:
4987       g_value_set_object (value, priv->content);
4988       break;
4989
4990     case PROP_CONTENT_GRAVITY:
4991       g_value_set_enum (value, priv->content_gravity);
4992       break;
4993
4994     case PROP_CONTENT_BOX:
4995       {
4996         ClutterActorBox box = { 0, };
4997
4998         clutter_actor_get_content_box (actor, &box);
4999         g_value_set_boxed (value, &box);
5000       }
5001       break;
5002
5003     case PROP_MINIFICATION_FILTER:
5004       g_value_set_enum (value, priv->min_filter);
5005       break;
5006
5007     case PROP_MAGNIFICATION_FILTER:
5008       g_value_set_enum (value, priv->mag_filter);
5009       break;
5010
5011     default:
5012       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5013       break;
5014     }
5015 }
5016
5017 static void
5018 clutter_actor_dispose (GObject *object)
5019 {
5020   ClutterActor *self = CLUTTER_ACTOR (object);
5021   ClutterActorPrivate *priv = self->priv;
5022
5023   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5024                 priv->id,
5025                 g_type_name (G_OBJECT_TYPE (self)),
5026                 object->ref_count);
5027
5028   g_signal_emit (self, actor_signals[DESTROY], 0);
5029
5030   /* avoid recursing when called from clutter_actor_destroy() */
5031   if (priv->parent != NULL)
5032     {
5033       ClutterActor *parent = priv->parent;
5034
5035       /* go through the Container implementation unless this
5036        * is an internal child and has been marked as such.
5037        *
5038        * removing the actor from its parent will reset the
5039        * realized and mapped states.
5040        */
5041       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5042         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5043       else
5044         clutter_actor_remove_child_internal (parent, self,
5045                                              REMOVE_CHILD_LEGACY_FLAGS);
5046     }
5047
5048   /* parent must be gone at this point */
5049   g_assert (priv->parent == NULL);
5050
5051   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5052     {
5053       /* can't be mapped or realized with no parent */
5054       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5055       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5056     }
5057
5058   g_clear_object (&priv->pango_context);
5059   g_clear_object (&priv->actions);
5060   g_clear_object (&priv->constraints);
5061   g_clear_object (&priv->effects);
5062   g_clear_object (&priv->flatten_effect);
5063
5064   if (priv->layout_manager != NULL)
5065     {
5066       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5067       g_clear_object (&priv->layout_manager);
5068     }
5069
5070   if (priv->content != NULL)
5071     {
5072       _clutter_content_detached (priv->content, self);
5073       g_clear_object (&priv->content);
5074     }
5075
5076   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5077 }
5078
5079 static void
5080 clutter_actor_finalize (GObject *object)
5081 {
5082   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5083
5084   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5085                 priv->name != NULL ? priv->name : "<none>",
5086                 priv->id,
5087                 g_type_name (G_OBJECT_TYPE (object)));
5088
5089   _clutter_context_release_id (priv->id);
5090
5091   g_free (priv->name);
5092
5093   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5094 }
5095
5096
5097 /**
5098  * clutter_actor_get_accessible:
5099  * @self: a #ClutterActor
5100  *
5101  * Returns the accessible object that describes the actor to an
5102  * assistive technology.
5103  *
5104  * If no class-specific #AtkObject implementation is available for the
5105  * actor instance in question, it will inherit an #AtkObject
5106  * implementation from the first ancestor class for which such an
5107  * implementation is defined.
5108  *
5109  * The documentation of the <ulink
5110  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5111  * library contains more information about accessible objects and
5112  * their uses.
5113  *
5114  * Returns: (transfer none): the #AtkObject associated with @actor
5115  */
5116 AtkObject *
5117 clutter_actor_get_accessible (ClutterActor *self)
5118 {
5119   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5120
5121   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5122 }
5123
5124 static AtkObject *
5125 clutter_actor_real_get_accessible (ClutterActor *actor)
5126 {
5127   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5128 }
5129
5130 static AtkObject *
5131 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5132 {
5133   AtkObject *accessible;
5134
5135   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5136   if (accessible != NULL)
5137     g_object_ref (accessible);
5138
5139   return accessible;
5140 }
5141
5142 static void
5143 atk_implementor_iface_init (AtkImplementorIface *iface)
5144 {
5145   iface->ref_accessible = _clutter_actor_ref_accessible;
5146 }
5147
5148 static gboolean
5149 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5150                                            ClutterPaintVolume *volume)
5151 {
5152   ClutterActorPrivate *priv = self->priv;
5153   gboolean res = FALSE;
5154
5155   /* we start from the allocation */
5156   clutter_paint_volume_set_width (volume,
5157                                   priv->allocation.x2 - priv->allocation.x1);
5158   clutter_paint_volume_set_height (volume,
5159                                    priv->allocation.y2 - priv->allocation.y1);
5160
5161   /* if the actor has a clip set then we have a pretty definite
5162    * size for the paint volume: the actor cannot possibly paint
5163    * outside the clip region.
5164    */
5165   if (priv->clip_to_allocation)
5166     {
5167       /* the allocation has already been set, so we just flip the
5168        * return value
5169        */
5170       res = TRUE;
5171     }
5172   else
5173     {
5174       ClutterActor *child;
5175
5176       if (priv->has_clip &&
5177           priv->clip.width >= 0 &&
5178           priv->clip.height >= 0)
5179         {
5180           ClutterVertex origin;
5181
5182           origin.x = priv->clip.x;
5183           origin.y = priv->clip.y;
5184           origin.z = 0;
5185
5186           clutter_paint_volume_set_origin (volume, &origin);
5187           clutter_paint_volume_set_width (volume, priv->clip.width);
5188           clutter_paint_volume_set_height (volume, priv->clip.height);
5189
5190           res = TRUE;
5191         }
5192
5193       /* if we don't have children we just bail out here... */
5194       if (priv->n_children == 0)
5195         return res;
5196
5197       /* ...but if we have children then we ask for their paint volume in
5198        * our coordinates. if any of our children replies that it doesn't
5199        * have a paint volume, we bail out
5200        */
5201       for (child = priv->first_child;
5202            child != NULL;
5203            child = child->priv->next_sibling)
5204         {
5205           const ClutterPaintVolume *child_volume;
5206
5207           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5208           if (child_volume == NULL)
5209             {
5210               res = FALSE;
5211               break;
5212             }
5213
5214           clutter_paint_volume_union (volume, child_volume);
5215           res = TRUE;
5216         }
5217     }
5218
5219   return res;
5220
5221 }
5222
5223 static gboolean
5224 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5225                                      ClutterPaintVolume *volume)
5226 {
5227   ClutterActorClass *klass;
5228   gboolean res;
5229
5230   klass = CLUTTER_ACTOR_GET_CLASS (self);
5231
5232   /* XXX - this thoroughly sucks, but we don't want to penalize users
5233    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5234    * redraw. This should go away in 2.0.
5235    */
5236   if (klass->paint == clutter_actor_real_paint &&
5237       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5238     {
5239       res = TRUE;
5240     }
5241   else
5242     {
5243       /* this is the default return value: we cannot know if a class
5244        * is going to paint outside its allocation, so we take the
5245        * conservative approach.
5246        */
5247       res = FALSE;
5248     }
5249
5250   if (clutter_actor_update_default_paint_volume (self, volume))
5251     return res;
5252
5253   return FALSE;
5254 }
5255
5256 /**
5257  * clutter_actor_get_default_paint_volume:
5258  * @self: a #ClutterActor
5259  *
5260  * Retrieves the default paint volume for @self.
5261  *
5262  * This function provides the same #ClutterPaintVolume that would be
5263  * computed by the default implementation inside #ClutterActor of the
5264  * #ClutterActorClass.get_paint_volume() virtual function.
5265  *
5266  * This function should only be used by #ClutterActor subclasses that
5267  * cannot chain up to the parent implementation when computing their
5268  * paint volume.
5269  *
5270  * Return value: (transfer none): a pointer to the default
5271  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5272  *   the actor could not compute a valid paint volume. The returned value
5273  *   is not guaranteed to be stable across multiple frames, so if you
5274  *   want to retain it, you will need to copy it using
5275  *   clutter_paint_volume_copy().
5276  *
5277  * Since: 1.10
5278  */
5279 const ClutterPaintVolume *
5280 clutter_actor_get_default_paint_volume (ClutterActor *self)
5281 {
5282   ClutterPaintVolume volume;
5283   ClutterPaintVolume *res;
5284
5285   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5286
5287   res = NULL;
5288   _clutter_paint_volume_init_static (&volume, self);
5289   if (clutter_actor_update_default_paint_volume (self, &volume))
5290     {
5291       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5292
5293       if (stage != NULL)
5294         {
5295           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5296           _clutter_paint_volume_copy_static (&volume, res);
5297         }
5298     }
5299
5300   clutter_paint_volume_free (&volume);
5301
5302   return res;
5303 }
5304
5305 static gboolean
5306 clutter_actor_real_has_overlaps (ClutterActor *self)
5307 {
5308   /* By default we'll assume that all actors need an offscreen redirect to get
5309    * the correct opacity. Actors such as ClutterTexture that would never need
5310    * an offscreen redirect can override this to return FALSE. */
5311   return TRUE;
5312 }
5313
5314 static void
5315 clutter_actor_real_destroy (ClutterActor *actor)
5316 {
5317   ClutterActorIter iter;
5318
5319   g_object_freeze_notify (G_OBJECT (actor));
5320
5321   clutter_actor_iter_init (&iter, actor);
5322   while (clutter_actor_iter_next (&iter, NULL))
5323     clutter_actor_iter_destroy (&iter);
5324
5325   g_object_thaw_notify (G_OBJECT (actor));
5326 }
5327
5328 static GObject *
5329 clutter_actor_constructor (GType gtype,
5330                            guint n_props,
5331                            GObjectConstructParam *props)
5332 {
5333   GObjectClass *gobject_class;
5334   ClutterActor *self;
5335   GObject *retval;
5336
5337   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5338   retval = gobject_class->constructor (gtype, n_props, props);
5339   self = CLUTTER_ACTOR (retval);
5340
5341   if (self->priv->layout_manager == NULL)
5342     {
5343       ClutterLayoutManager *default_layout;
5344
5345       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5346
5347       default_layout = clutter_fixed_layout_new ();
5348       clutter_actor_set_layout_manager (self, default_layout);
5349     }
5350
5351   return retval;
5352 }
5353
5354 static void
5355 clutter_actor_class_init (ClutterActorClass *klass)
5356 {
5357   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5358
5359   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5360   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5361   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5362   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5363
5364   object_class->constructor = clutter_actor_constructor;
5365   object_class->set_property = clutter_actor_set_property;
5366   object_class->get_property = clutter_actor_get_property;
5367   object_class->dispose = clutter_actor_dispose;
5368   object_class->finalize = clutter_actor_finalize;
5369
5370   klass->show = clutter_actor_real_show;
5371   klass->show_all = clutter_actor_show;
5372   klass->hide = clutter_actor_real_hide;
5373   klass->hide_all = clutter_actor_hide;
5374   klass->map = clutter_actor_real_map;
5375   klass->unmap = clutter_actor_real_unmap;
5376   klass->unrealize = clutter_actor_real_unrealize;
5377   klass->pick = clutter_actor_real_pick;
5378   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5379   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5380   klass->allocate = clutter_actor_real_allocate;
5381   klass->queue_redraw = clutter_actor_real_queue_redraw;
5382   klass->queue_relayout = clutter_actor_real_queue_relayout;
5383   klass->apply_transform = clutter_actor_real_apply_transform;
5384   klass->get_accessible = clutter_actor_real_get_accessible;
5385   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5386   klass->has_overlaps = clutter_actor_real_has_overlaps;
5387   klass->paint = clutter_actor_real_paint;
5388   klass->destroy = clutter_actor_real_destroy;
5389
5390   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5391
5392   /**
5393    * ClutterActor:x:
5394    *
5395    * X coordinate of the actor in pixels. If written, forces a fixed
5396    * position for the actor. If read, returns the fixed position if any,
5397    * otherwise the allocation if available, otherwise 0.
5398    *
5399    * The #ClutterActor:x property is animatable.
5400    */
5401   obj_props[PROP_X] =
5402     g_param_spec_float ("x",
5403                         P_("X coordinate"),
5404                         P_("X coordinate of the actor"),
5405                         -G_MAXFLOAT, G_MAXFLOAT,
5406                         0.0,
5407                         G_PARAM_READWRITE |
5408                         G_PARAM_STATIC_STRINGS |
5409                         CLUTTER_PARAM_ANIMATABLE);
5410
5411   /**
5412    * ClutterActor:y:
5413    *
5414    * Y coordinate of the actor in pixels. If written, forces a fixed
5415    * position for the actor.  If read, returns the fixed position if
5416    * any, otherwise the allocation if available, otherwise 0.
5417    *
5418    * The #ClutterActor:y property is animatable.
5419    */
5420   obj_props[PROP_Y] =
5421     g_param_spec_float ("y",
5422                         P_("Y coordinate"),
5423                         P_("Y coordinate of the actor"),
5424                         -G_MAXFLOAT, G_MAXFLOAT,
5425                         0.0,
5426                         G_PARAM_READWRITE |
5427                         G_PARAM_STATIC_STRINGS |
5428                         CLUTTER_PARAM_ANIMATABLE);
5429
5430   /**
5431    * ClutterActor:width:
5432    *
5433    * Width of the actor (in pixels). If written, forces the minimum and
5434    * natural size request of the actor to the given width. If read, returns
5435    * the allocated width if available, otherwise the width request.
5436    *
5437    * The #ClutterActor:width property is animatable.
5438    */
5439   obj_props[PROP_WIDTH] =
5440     g_param_spec_float ("width",
5441                         P_("Width"),
5442                         P_("Width of the actor"),
5443                         0.0, G_MAXFLOAT,
5444                         0.0,
5445                         G_PARAM_READWRITE |
5446                         G_PARAM_STATIC_STRINGS |
5447                         CLUTTER_PARAM_ANIMATABLE);
5448
5449   /**
5450    * ClutterActor:height:
5451    *
5452    * Height of the actor (in pixels).  If written, forces the minimum and
5453    * natural size request of the actor to the given height. If read, returns
5454    * the allocated height if available, otherwise the height request.
5455    *
5456    * The #ClutterActor:height property is animatable.
5457    */
5458   obj_props[PROP_HEIGHT] =
5459     g_param_spec_float ("height",
5460                         P_("Height"),
5461                         P_("Height of the actor"),
5462                         0.0, G_MAXFLOAT,
5463                         0.0,
5464                         G_PARAM_READWRITE |
5465                         G_PARAM_STATIC_STRINGS |
5466                         CLUTTER_PARAM_ANIMATABLE);
5467
5468   /**
5469    * ClutterActor:fixed-x:
5470    *
5471    * The fixed X position of the actor in pixels.
5472    *
5473    * Writing this property sets #ClutterActor:fixed-position-set
5474    * property as well, as a side effect
5475    *
5476    * Since: 0.8
5477    */
5478   obj_props[PROP_FIXED_X] =
5479     g_param_spec_float ("fixed-x",
5480                         P_("Fixed X"),
5481                         P_("Forced X position of the actor"),
5482                         -G_MAXFLOAT, G_MAXFLOAT,
5483                         0.0,
5484                         CLUTTER_PARAM_READWRITE);
5485
5486   /**
5487    * ClutterActor:fixed-y:
5488    *
5489    * The fixed Y position of the actor in pixels.
5490    *
5491    * Writing this property sets the #ClutterActor:fixed-position-set
5492    * property as well, as a side effect
5493    *
5494    * Since: 0.8
5495    */
5496   obj_props[PROP_FIXED_Y] =
5497     g_param_spec_float ("fixed-y",
5498                         P_("Fixed Y"),
5499                         P_("Forced Y position of the actor"),
5500                         -G_MAXFLOAT, G_MAXFLOAT,
5501                         0,
5502                         CLUTTER_PARAM_READWRITE);
5503
5504   /**
5505    * ClutterActor:fixed-position-set:
5506    *
5507    * This flag controls whether the #ClutterActor:fixed-x and
5508    * #ClutterActor:fixed-y properties are used
5509    *
5510    * Since: 0.8
5511    */
5512   obj_props[PROP_FIXED_POSITION_SET] =
5513     g_param_spec_boolean ("fixed-position-set",
5514                           P_("Fixed position set"),
5515                           P_("Whether to use fixed positioning for the actor"),
5516                           FALSE,
5517                           CLUTTER_PARAM_READWRITE);
5518
5519   /**
5520    * ClutterActor:min-width:
5521    *
5522    * A forced minimum width request for the actor, in pixels
5523    *
5524    * Writing this property sets the #ClutterActor:min-width-set property
5525    * as well, as a side effect.
5526    *
5527    *This property overrides the usual width request of the actor.
5528    *
5529    * Since: 0.8
5530    */
5531   obj_props[PROP_MIN_WIDTH] =
5532     g_param_spec_float ("min-width",
5533                         P_("Min Width"),
5534                         P_("Forced minimum width request for the actor"),
5535                         0.0, G_MAXFLOAT,
5536                         0.0,
5537                         CLUTTER_PARAM_READWRITE);
5538
5539   /**
5540    * ClutterActor:min-height:
5541    *
5542    * A forced minimum height request for the actor, in pixels
5543    *
5544    * Writing this property sets the #ClutterActor:min-height-set property
5545    * as well, as a side effect. This property overrides the usual height
5546    * request of the actor.
5547    *
5548    * Since: 0.8
5549    */
5550   obj_props[PROP_MIN_HEIGHT] =
5551     g_param_spec_float ("min-height",
5552                         P_("Min Height"),
5553                         P_("Forced minimum height request for the actor"),
5554                         0.0, G_MAXFLOAT,
5555                         0.0,
5556                         CLUTTER_PARAM_READWRITE);
5557
5558   /**
5559    * ClutterActor:natural-width:
5560    *
5561    * A forced natural width request for the actor, in pixels
5562    *
5563    * Writing this property sets the #ClutterActor:natural-width-set
5564    * property as well, as a side effect. This property overrides the
5565    * usual width request of the actor
5566    *
5567    * Since: 0.8
5568    */
5569   obj_props[PROP_NATURAL_WIDTH] =
5570     g_param_spec_float ("natural-width",
5571                         P_("Natural Width"),
5572                         P_("Forced natural width request for the actor"),
5573                         0.0, G_MAXFLOAT,
5574                         0.0,
5575                         CLUTTER_PARAM_READWRITE);
5576
5577   /**
5578    * ClutterActor:natural-height:
5579    *
5580    * A forced natural height request for the actor, in pixels
5581    *
5582    * Writing this property sets the #ClutterActor:natural-height-set
5583    * property as well, as a side effect. This property overrides the
5584    * usual height request of the actor
5585    *
5586    * Since: 0.8
5587    */
5588   obj_props[PROP_NATURAL_HEIGHT] =
5589     g_param_spec_float ("natural-height",
5590                         P_("Natural Height"),
5591                         P_("Forced natural height request for the actor"),
5592                         0.0, G_MAXFLOAT,
5593                         0.0,
5594                         CLUTTER_PARAM_READWRITE);
5595
5596   /**
5597    * ClutterActor:min-width-set:
5598    *
5599    * This flag controls whether the #ClutterActor:min-width property
5600    * is used
5601    *
5602    * Since: 0.8
5603    */
5604   obj_props[PROP_MIN_WIDTH_SET] =
5605     g_param_spec_boolean ("min-width-set",
5606                           P_("Minimum width set"),
5607                           P_("Whether to use the min-width property"),
5608                           FALSE,
5609                           CLUTTER_PARAM_READWRITE);
5610
5611   /**
5612    * ClutterActor:min-height-set:
5613    *
5614    * This flag controls whether the #ClutterActor:min-height property
5615    * is used
5616    *
5617    * Since: 0.8
5618    */
5619   obj_props[PROP_MIN_HEIGHT_SET] =
5620     g_param_spec_boolean ("min-height-set",
5621                           P_("Minimum height set"),
5622                           P_("Whether to use the min-height property"),
5623                           FALSE,
5624                           CLUTTER_PARAM_READWRITE);
5625
5626   /**
5627    * ClutterActor:natural-width-set:
5628    *
5629    * This flag controls whether the #ClutterActor:natural-width property
5630    * is used
5631    *
5632    * Since: 0.8
5633    */
5634   obj_props[PROP_NATURAL_WIDTH_SET] =
5635     g_param_spec_boolean ("natural-width-set",
5636                           P_("Natural width set"),
5637                           P_("Whether to use the natural-width property"),
5638                           FALSE,
5639                           CLUTTER_PARAM_READWRITE);
5640
5641   /**
5642    * ClutterActor:natural-height-set:
5643    *
5644    * This flag controls whether the #ClutterActor:natural-height property
5645    * is used
5646    *
5647    * Since: 0.8
5648    */
5649   obj_props[PROP_NATURAL_HEIGHT_SET] =
5650     g_param_spec_boolean ("natural-height-set",
5651                           P_("Natural height set"),
5652                           P_("Whether to use the natural-height property"),
5653                           FALSE,
5654                           CLUTTER_PARAM_READWRITE);
5655
5656   /**
5657    * ClutterActor:allocation:
5658    *
5659    * The allocation for the actor, in pixels
5660    *
5661    * This is property is read-only, but you might monitor it to know when an
5662    * actor moves or resizes
5663    *
5664    * Since: 0.8
5665    */
5666   obj_props[PROP_ALLOCATION] =
5667     g_param_spec_boxed ("allocation",
5668                         P_("Allocation"),
5669                         P_("The actor's allocation"),
5670                         CLUTTER_TYPE_ACTOR_BOX,
5671                         CLUTTER_PARAM_READABLE);
5672
5673   /**
5674    * ClutterActor:request-mode:
5675    *
5676    * Request mode for the #ClutterActor. The request mode determines the
5677    * type of geometry management used by the actor, either height for width
5678    * (the default) or width for height.
5679    *
5680    * For actors implementing height for width, the parent container should get
5681    * the preferred width first, and then the preferred height for that width.
5682    *
5683    * For actors implementing width for height, the parent container should get
5684    * the preferred height first, and then the preferred width for that height.
5685    *
5686    * For instance:
5687    *
5688    * |[
5689    *   ClutterRequestMode mode;
5690    *   gfloat natural_width, min_width;
5691    *   gfloat natural_height, min_height;
5692    *
5693    *   mode = clutter_actor_get_request_mode (child);
5694    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5695    *     {
5696    *       clutter_actor_get_preferred_width (child, -1,
5697    *                                          &amp;min_width,
5698    *                                          &amp;natural_width);
5699    *       clutter_actor_get_preferred_height (child, natural_width,
5700    *                                           &amp;min_height,
5701    *                                           &amp;natural_height);
5702    *     }
5703    *   else
5704    *     {
5705    *       clutter_actor_get_preferred_height (child, -1,
5706    *                                           &amp;min_height,
5707    *                                           &amp;natural_height);
5708    *       clutter_actor_get_preferred_width (child, natural_height,
5709    *                                          &amp;min_width,
5710    *                                          &amp;natural_width);
5711    *     }
5712    * ]|
5713    *
5714    * will retrieve the minimum and natural width and height depending on the
5715    * preferred request mode of the #ClutterActor "child".
5716    *
5717    * The clutter_actor_get_preferred_size() function will implement this
5718    * check for you.
5719    *
5720    * Since: 0.8
5721    */
5722   obj_props[PROP_REQUEST_MODE] =
5723     g_param_spec_enum ("request-mode",
5724                        P_("Request Mode"),
5725                        P_("The actor's request mode"),
5726                        CLUTTER_TYPE_REQUEST_MODE,
5727                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5728                        CLUTTER_PARAM_READWRITE);
5729
5730   /**
5731    * ClutterActor:depth:
5732    *
5733    * The position of the actor on the Z axis.
5734    *
5735    * The #ClutterActor:depth property is relative to the parent's
5736    * modelview matrix.
5737    *
5738    * The #ClutterActor:depth property is animatable.
5739    *
5740    * Since: 0.6
5741    */
5742   obj_props[PROP_DEPTH] =
5743     g_param_spec_float ("depth",
5744                         P_("Depth"),
5745                         P_("Position on the Z axis"),
5746                         -G_MAXFLOAT, G_MAXFLOAT,
5747                         0.0,
5748                         G_PARAM_READWRITE |
5749                         G_PARAM_STATIC_STRINGS |
5750                         CLUTTER_PARAM_ANIMATABLE);
5751
5752   /**
5753    * ClutterActor:opacity:
5754    *
5755    * Opacity of an actor, between 0 (fully transparent) and
5756    * 255 (fully opaque)
5757    *
5758    * The #ClutterActor:opacity property is animatable.
5759    */
5760   obj_props[PROP_OPACITY] =
5761     g_param_spec_uint ("opacity",
5762                        P_("Opacity"),
5763                        P_("Opacity of an actor"),
5764                        0, 255,
5765                        255,
5766                        G_PARAM_READWRITE |
5767                        G_PARAM_STATIC_STRINGS |
5768                        CLUTTER_PARAM_ANIMATABLE);
5769
5770   /**
5771    * ClutterActor:offscreen-redirect:
5772    *
5773    * Determines the conditions in which the actor will be redirected
5774    * to an offscreen framebuffer while being painted. For example this
5775    * can be used to cache an actor in a framebuffer or for improved
5776    * handling of transparent actors. See
5777    * clutter_actor_set_offscreen_redirect() for details.
5778    *
5779    * Since: 1.8
5780    */
5781   obj_props[PROP_OFFSCREEN_REDIRECT] =
5782     g_param_spec_flags ("offscreen-redirect",
5783                         P_("Offscreen redirect"),
5784                         P_("Flags controlling when to flatten the actor into a single image"),
5785                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5786                         0,
5787                         CLUTTER_PARAM_READWRITE);
5788
5789   /**
5790    * ClutterActor:visible:
5791    *
5792    * Whether the actor is set to be visible or not
5793    *
5794    * See also #ClutterActor:mapped
5795    */
5796   obj_props[PROP_VISIBLE] =
5797     g_param_spec_boolean ("visible",
5798                           P_("Visible"),
5799                           P_("Whether the actor is visible or not"),
5800                           FALSE,
5801                           CLUTTER_PARAM_READWRITE);
5802
5803   /**
5804    * ClutterActor:mapped:
5805    *
5806    * Whether the actor is mapped (will be painted when the stage
5807    * to which it belongs is mapped)
5808    *
5809    * Since: 1.0
5810    */
5811   obj_props[PROP_MAPPED] =
5812     g_param_spec_boolean ("mapped",
5813                           P_("Mapped"),
5814                           P_("Whether the actor will be painted"),
5815                           FALSE,
5816                           CLUTTER_PARAM_READABLE);
5817
5818   /**
5819    * ClutterActor:realized:
5820    *
5821    * Whether the actor has been realized
5822    *
5823    * Since: 1.0
5824    */
5825   obj_props[PROP_REALIZED] =
5826     g_param_spec_boolean ("realized",
5827                           P_("Realized"),
5828                           P_("Whether the actor has been realized"),
5829                           FALSE,
5830                           CLUTTER_PARAM_READABLE);
5831
5832   /**
5833    * ClutterActor:reactive:
5834    *
5835    * Whether the actor is reactive to events or not
5836    *
5837    * Only reactive actors will emit event-related signals
5838    *
5839    * Since: 0.6
5840    */
5841   obj_props[PROP_REACTIVE] =
5842     g_param_spec_boolean ("reactive",
5843                           P_("Reactive"),
5844                           P_("Whether the actor is reactive to events"),
5845                           FALSE,
5846                           CLUTTER_PARAM_READWRITE);
5847
5848   /**
5849    * ClutterActor:has-clip:
5850    *
5851    * Whether the actor has the #ClutterActor:clip property set or not
5852    */
5853   obj_props[PROP_HAS_CLIP] =
5854     g_param_spec_boolean ("has-clip",
5855                           P_("Has Clip"),
5856                           P_("Whether the actor has a clip set"),
5857                           FALSE,
5858                           CLUTTER_PARAM_READABLE);
5859
5860   /**
5861    * ClutterActor:clip:
5862    *
5863    * The clip region for the actor, in actor-relative coordinates
5864    *
5865    * Every part of the actor outside the clip region will not be
5866    * painted
5867    */
5868   obj_props[PROP_CLIP] =
5869     g_param_spec_boxed ("clip",
5870                         P_("Clip"),
5871                         P_("The clip region for the actor"),
5872                         CLUTTER_TYPE_GEOMETRY,
5873                         CLUTTER_PARAM_READWRITE);
5874
5875   /**
5876    * ClutterActor:name:
5877    *
5878    * The name of the actor
5879    *
5880    * Since: 0.2
5881    */
5882   obj_props[PROP_NAME] =
5883     g_param_spec_string ("name",
5884                          P_("Name"),
5885                          P_("Name of the actor"),
5886                          NULL,
5887                          CLUTTER_PARAM_READWRITE);
5888
5889   /**
5890    * ClutterActor:scale-x:
5891    *
5892    * The horizontal scale of the actor.
5893    *
5894    * The #ClutterActor:scale-x property is animatable.
5895    *
5896    * Since: 0.6
5897    */
5898   obj_props[PROP_SCALE_X] =
5899     g_param_spec_double ("scale-x",
5900                          P_("Scale X"),
5901                          P_("Scale factor on the X axis"),
5902                          0.0, G_MAXDOUBLE,
5903                          1.0,
5904                          G_PARAM_READWRITE |
5905                          G_PARAM_STATIC_STRINGS |
5906                          CLUTTER_PARAM_ANIMATABLE);
5907
5908   /**
5909    * ClutterActor:scale-y:
5910    *
5911    * The vertical scale of the actor.
5912    *
5913    * The #ClutterActor:scale-y property is animatable.
5914    *
5915    * Since: 0.6
5916    */
5917   obj_props[PROP_SCALE_Y] =
5918     g_param_spec_double ("scale-y",
5919                          P_("Scale Y"),
5920                          P_("Scale factor on the Y axis"),
5921                          0.0, G_MAXDOUBLE,
5922                          1.0,
5923                          G_PARAM_READWRITE |
5924                          G_PARAM_STATIC_STRINGS |
5925                          CLUTTER_PARAM_ANIMATABLE);
5926
5927   /**
5928    * ClutterActor:scale-center-x:
5929    *
5930    * The horizontal center point for scaling
5931    *
5932    * Since: 1.0
5933    */
5934   obj_props[PROP_SCALE_CENTER_X] =
5935     g_param_spec_float ("scale-center-x",
5936                         P_("Scale Center X"),
5937                         P_("Horizontal scale center"),
5938                         -G_MAXFLOAT, G_MAXFLOAT,
5939                         0.0,
5940                         CLUTTER_PARAM_READWRITE);
5941
5942   /**
5943    * ClutterActor:scale-center-y:
5944    *
5945    * The vertical center point for scaling
5946    *
5947    * Since: 1.0
5948    */
5949   obj_props[PROP_SCALE_CENTER_Y] =
5950     g_param_spec_float ("scale-center-y",
5951                         P_("Scale Center Y"),
5952                         P_("Vertical scale center"),
5953                         -G_MAXFLOAT, G_MAXFLOAT,
5954                         0.0,
5955                         CLUTTER_PARAM_READWRITE);
5956
5957   /**
5958    * ClutterActor:scale-gravity:
5959    *
5960    * The center point for scaling expressed as a #ClutterGravity
5961    *
5962    * Since: 1.0
5963    */
5964   obj_props[PROP_SCALE_GRAVITY] =
5965     g_param_spec_enum ("scale-gravity",
5966                        P_("Scale Gravity"),
5967                        P_("The center of scaling"),
5968                        CLUTTER_TYPE_GRAVITY,
5969                        CLUTTER_GRAVITY_NONE,
5970                        CLUTTER_PARAM_READWRITE);
5971
5972   /**
5973    * ClutterActor:rotation-angle-x:
5974    *
5975    * The rotation angle on the X axis.
5976    *
5977    * The #ClutterActor:rotation-angle-x property is animatable.
5978    *
5979    * Since: 0.6
5980    */
5981   obj_props[PROP_ROTATION_ANGLE_X] =
5982     g_param_spec_double ("rotation-angle-x",
5983                          P_("Rotation Angle X"),
5984                          P_("The rotation angle on the X axis"),
5985                          -G_MAXDOUBLE, G_MAXDOUBLE,
5986                          0.0,
5987                          G_PARAM_READWRITE |
5988                          G_PARAM_STATIC_STRINGS |
5989                          CLUTTER_PARAM_ANIMATABLE);
5990
5991   /**
5992    * ClutterActor:rotation-angle-y:
5993    *
5994    * The rotation angle on the Y axis
5995    *
5996    * The #ClutterActor:rotation-angle-y property is animatable.
5997    *
5998    * Since: 0.6
5999    */
6000   obj_props[PROP_ROTATION_ANGLE_Y] =
6001     g_param_spec_double ("rotation-angle-y",
6002                          P_("Rotation Angle Y"),
6003                          P_("The rotation angle on the Y axis"),
6004                          -G_MAXDOUBLE, G_MAXDOUBLE,
6005                          0.0,
6006                          G_PARAM_READWRITE |
6007                          G_PARAM_STATIC_STRINGS |
6008                          CLUTTER_PARAM_ANIMATABLE);
6009
6010   /**
6011    * ClutterActor:rotation-angle-z:
6012    *
6013    * The rotation angle on the Z axis
6014    *
6015    * The #ClutterActor:rotation-angle-z property is animatable.
6016    *
6017    * Since: 0.6
6018    */
6019   obj_props[PROP_ROTATION_ANGLE_Z] =
6020     g_param_spec_double ("rotation-angle-z",
6021                          P_("Rotation Angle Z"),
6022                          P_("The rotation angle on the Z axis"),
6023                          -G_MAXDOUBLE, G_MAXDOUBLE,
6024                          0.0,
6025                          G_PARAM_READWRITE |
6026                          G_PARAM_STATIC_STRINGS |
6027                          CLUTTER_PARAM_ANIMATABLE);
6028
6029   /**
6030    * ClutterActor:rotation-center-x:
6031    *
6032    * The rotation center on the X axis.
6033    *
6034    * Since: 0.6
6035    */
6036   obj_props[PROP_ROTATION_CENTER_X] =
6037     g_param_spec_boxed ("rotation-center-x",
6038                         P_("Rotation Center X"),
6039                         P_("The rotation center on the X axis"),
6040                         CLUTTER_TYPE_VERTEX,
6041                         CLUTTER_PARAM_READWRITE);
6042
6043   /**
6044    * ClutterActor:rotation-center-y:
6045    *
6046    * The rotation center on the Y axis.
6047    *
6048    * Since: 0.6
6049    */
6050   obj_props[PROP_ROTATION_CENTER_Y] =
6051     g_param_spec_boxed ("rotation-center-y",
6052                         P_("Rotation Center Y"),
6053                         P_("The rotation center on the Y axis"),
6054                         CLUTTER_TYPE_VERTEX,
6055                         CLUTTER_PARAM_READWRITE);
6056
6057   /**
6058    * ClutterActor:rotation-center-z:
6059    *
6060    * The rotation center on the Z axis.
6061    *
6062    * Since: 0.6
6063    */
6064   obj_props[PROP_ROTATION_CENTER_Z] =
6065     g_param_spec_boxed ("rotation-center-z",
6066                         P_("Rotation Center Z"),
6067                         P_("The rotation center on the Z axis"),
6068                         CLUTTER_TYPE_VERTEX,
6069                         CLUTTER_PARAM_READWRITE);
6070
6071   /**
6072    * ClutterActor:rotation-center-z-gravity:
6073    *
6074    * The rotation center on the Z axis expressed as a #ClutterGravity.
6075    *
6076    * Since: 1.0
6077    */
6078   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6079     g_param_spec_enum ("rotation-center-z-gravity",
6080                        P_("Rotation Center Z Gravity"),
6081                        P_("Center point for rotation around the Z axis"),
6082                        CLUTTER_TYPE_GRAVITY,
6083                        CLUTTER_GRAVITY_NONE,
6084                        CLUTTER_PARAM_READWRITE);
6085
6086   /**
6087    * ClutterActor:anchor-x:
6088    *
6089    * The X coordinate of an actor's anchor point, relative to
6090    * the actor coordinate space, in pixels
6091    *
6092    * Since: 0.8
6093    */
6094   obj_props[PROP_ANCHOR_X] =
6095     g_param_spec_float ("anchor-x",
6096                         P_("Anchor X"),
6097                         P_("X coordinate of the anchor point"),
6098                         -G_MAXFLOAT, G_MAXFLOAT,
6099                         0,
6100                         CLUTTER_PARAM_READWRITE);
6101
6102   /**
6103    * ClutterActor:anchor-y:
6104    *
6105    * The Y coordinate of an actor's anchor point, relative to
6106    * the actor coordinate space, in pixels
6107    *
6108    * Since: 0.8
6109    */
6110   obj_props[PROP_ANCHOR_Y] =
6111     g_param_spec_float ("anchor-y",
6112                         P_("Anchor Y"),
6113                         P_("Y coordinate of the anchor point"),
6114                         -G_MAXFLOAT, G_MAXFLOAT,
6115                         0,
6116                         CLUTTER_PARAM_READWRITE);
6117
6118   /**
6119    * ClutterActor:anchor-gravity:
6120    *
6121    * The anchor point expressed as a #ClutterGravity
6122    *
6123    * Since: 1.0
6124    */
6125   obj_props[PROP_ANCHOR_GRAVITY] =
6126     g_param_spec_enum ("anchor-gravity",
6127                        P_("Anchor Gravity"),
6128                        P_("The anchor point as a ClutterGravity"),
6129                        CLUTTER_TYPE_GRAVITY,
6130                        CLUTTER_GRAVITY_NONE,
6131                        CLUTTER_PARAM_READWRITE);
6132
6133   /**
6134    * ClutterActor:show-on-set-parent:
6135    *
6136    * If %TRUE, the actor is automatically shown when parented.
6137    *
6138    * Calling clutter_actor_hide() on an actor which has not been
6139    * parented will set this property to %FALSE as a side effect.
6140    *
6141    * Since: 0.8
6142    */
6143   obj_props[PROP_SHOW_ON_SET_PARENT] =
6144     g_param_spec_boolean ("show-on-set-parent",
6145                           P_("Show on set parent"),
6146                           P_("Whether the actor is shown when parented"),
6147                           TRUE,
6148                           CLUTTER_PARAM_READWRITE);
6149
6150   /**
6151    * ClutterActor:clip-to-allocation:
6152    *
6153    * Whether the clip region should track the allocated area
6154    * of the actor.
6155    *
6156    * This property is ignored if a clip area has been explicitly
6157    * set using clutter_actor_set_clip().
6158    *
6159    * Since: 1.0
6160    */
6161   obj_props[PROP_CLIP_TO_ALLOCATION] =
6162     g_param_spec_boolean ("clip-to-allocation",
6163                           P_("Clip to Allocation"),
6164                           P_("Sets the clip region to track the actor's allocation"),
6165                           FALSE,
6166                           CLUTTER_PARAM_READWRITE);
6167
6168   /**
6169    * ClutterActor:text-direction:
6170    *
6171    * The direction of the text inside a #ClutterActor.
6172    *
6173    * Since: 1.0
6174    */
6175   obj_props[PROP_TEXT_DIRECTION] =
6176     g_param_spec_enum ("text-direction",
6177                        P_("Text Direction"),
6178                        P_("Direction of the text"),
6179                        CLUTTER_TYPE_TEXT_DIRECTION,
6180                        CLUTTER_TEXT_DIRECTION_LTR,
6181                        CLUTTER_PARAM_READWRITE);
6182
6183   /**
6184    * ClutterActor:has-pointer:
6185    *
6186    * Whether the actor contains the pointer of a #ClutterInputDevice
6187    * or not.
6188    *
6189    * Since: 1.2
6190    */
6191   obj_props[PROP_HAS_POINTER] =
6192     g_param_spec_boolean ("has-pointer",
6193                           P_("Has Pointer"),
6194                           P_("Whether the actor contains the pointer of an input device"),
6195                           FALSE,
6196                           CLUTTER_PARAM_READABLE);
6197
6198   /**
6199    * ClutterActor:actions:
6200    *
6201    * Adds a #ClutterAction to the actor
6202    *
6203    * Since: 1.4
6204    */
6205   obj_props[PROP_ACTIONS] =
6206     g_param_spec_object ("actions",
6207                          P_("Actions"),
6208                          P_("Adds an action to the actor"),
6209                          CLUTTER_TYPE_ACTION,
6210                          CLUTTER_PARAM_WRITABLE);
6211
6212   /**
6213    * ClutterActor:constraints:
6214    *
6215    * Adds a #ClutterConstraint to the actor
6216    *
6217    * Since: 1.4
6218    */
6219   obj_props[PROP_CONSTRAINTS] =
6220     g_param_spec_object ("constraints",
6221                          P_("Constraints"),
6222                          P_("Adds a constraint to the actor"),
6223                          CLUTTER_TYPE_CONSTRAINT,
6224                          CLUTTER_PARAM_WRITABLE);
6225
6226   /**
6227    * ClutterActor:effect:
6228    *
6229    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6230    *
6231    * Since: 1.4
6232    */
6233   obj_props[PROP_EFFECT] =
6234     g_param_spec_object ("effect",
6235                          P_("Effect"),
6236                          P_("Add an effect to be applied on the actor"),
6237                          CLUTTER_TYPE_EFFECT,
6238                          CLUTTER_PARAM_WRITABLE);
6239
6240   /**
6241    * ClutterActor:layout-manager:
6242    *
6243    * A delegate object for controlling the layout of the children of
6244    * an actor.
6245    *
6246    * Since: 1.10
6247    */
6248   obj_props[PROP_LAYOUT_MANAGER] =
6249     g_param_spec_object ("layout-manager",
6250                          P_("Layout Manager"),
6251                          P_("The object controlling the layout of an actor's children"),
6252                          CLUTTER_TYPE_LAYOUT_MANAGER,
6253                          CLUTTER_PARAM_READWRITE);
6254
6255
6256   /**
6257    * ClutterActor:x-align:
6258    *
6259    * The alignment of an actor on the X axis, if the actor has been given
6260    * extra space for its allocation.
6261    *
6262    * Since: 1.10
6263    */
6264   obj_props[PROP_X_ALIGN] =
6265     g_param_spec_enum ("x-align",
6266                        P_("X Alignment"),
6267                        P_("The alignment of the actor on the X axis within its allocation"),
6268                        CLUTTER_TYPE_ACTOR_ALIGN,
6269                        CLUTTER_ACTOR_ALIGN_FILL,
6270                        CLUTTER_PARAM_READWRITE);
6271
6272   /**
6273    * ClutterActor:y-align:
6274    *
6275    * The alignment of an actor on the Y axis, if the actor has been given
6276    * extra space for its allocation.
6277    *
6278    * Since: 1.10
6279    */
6280   obj_props[PROP_Y_ALIGN] =
6281     g_param_spec_enum ("y-align",
6282                        P_("Y Alignment"),
6283                        P_("The alignment of the actor on the Y axis within its allocation"),
6284                        CLUTTER_TYPE_ACTOR_ALIGN,
6285                        CLUTTER_ACTOR_ALIGN_FILL,
6286                        CLUTTER_PARAM_READWRITE);
6287
6288   /**
6289    * ClutterActor:margin-top:
6290    *
6291    * The margin (in pixels) from the top of the actor.
6292    *
6293    * This property adds a margin to the actor's preferred size; the margin
6294    * will be automatically taken into account when allocating the actor.
6295    *
6296    * Since: 1.10
6297    */
6298   obj_props[PROP_MARGIN_TOP] =
6299     g_param_spec_float ("margin-top",
6300                         P_("Margin Top"),
6301                         P_("Extra space at the top"),
6302                         0.0, G_MAXFLOAT,
6303                         0.0,
6304                         CLUTTER_PARAM_READWRITE);
6305
6306   /**
6307    * ClutterActor:margin-bottom:
6308    *
6309    * The margin (in pixels) from the bottom of the actor.
6310    *
6311    * This property adds a margin to the actor's preferred size; the margin
6312    * will be automatically taken into account when allocating the actor.
6313    *
6314    * Since: 1.10
6315    */
6316   obj_props[PROP_MARGIN_BOTTOM] =
6317     g_param_spec_float ("margin-bottom",
6318                         P_("Margin Bottom"),
6319                         P_("Extra space at the bottom"),
6320                         0.0, G_MAXFLOAT,
6321                         0.0,
6322                         CLUTTER_PARAM_READWRITE);
6323
6324   /**
6325    * ClutterActor:margin-left:
6326    *
6327    * The margin (in pixels) from the left of the actor.
6328    *
6329    * This property adds a margin to the actor's preferred size; the margin
6330    * will be automatically taken into account when allocating the actor.
6331    *
6332    * Since: 1.10
6333    */
6334   obj_props[PROP_MARGIN_LEFT] =
6335     g_param_spec_float ("margin-left",
6336                         P_("Margin Left"),
6337                         P_("Extra space at the left"),
6338                         0.0, G_MAXFLOAT,
6339                         0.0,
6340                         CLUTTER_PARAM_READWRITE);
6341
6342   /**
6343    * ClutterActor:margin-right:
6344    *
6345    * The margin (in pixels) from the right of the actor.
6346    *
6347    * This property adds a margin to the actor's preferred size; the margin
6348    * will be automatically taken into account when allocating the actor.
6349    *
6350    * Since: 1.10
6351    */
6352   obj_props[PROP_MARGIN_RIGHT] =
6353     g_param_spec_float ("margin-right",
6354                         P_("Margin Right"),
6355                         P_("Extra space at the right"),
6356                         0.0, G_MAXFLOAT,
6357                         0.0,
6358                         CLUTTER_PARAM_READWRITE);
6359
6360   /**
6361    * ClutterActor:background-color-set:
6362    *
6363    * Whether the #ClutterActor:background-color property has been set.
6364    *
6365    * Since: 1.10
6366    */
6367   obj_props[PROP_BACKGROUND_COLOR_SET] =
6368     g_param_spec_boolean ("background-color-set",
6369                           P_("Background Color Set"),
6370                           P_("Whether the background color is set"),
6371                           FALSE,
6372                           CLUTTER_PARAM_READABLE);
6373
6374   /**
6375    * ClutterActor:background-color:
6376    *
6377    * Paints a solid fill of the actor's allocation using the specified
6378    * color.
6379    *
6380    * The #ClutterActor:background-color property is animatable.
6381    *
6382    * Since: 1.10
6383    */
6384   obj_props[PROP_BACKGROUND_COLOR] =
6385     clutter_param_spec_color ("background-color",
6386                               P_("Background color"),
6387                               P_("The actor's background color"),
6388                               CLUTTER_COLOR_Transparent,
6389                               G_PARAM_READWRITE |
6390                               G_PARAM_STATIC_STRINGS |
6391                               CLUTTER_PARAM_ANIMATABLE);
6392
6393   /**
6394    * ClutterActor:first-child:
6395    *
6396    * The actor's first child.
6397    *
6398    * Since: 1.10
6399    */
6400   obj_props[PROP_FIRST_CHILD] =
6401     g_param_spec_object ("first-child",
6402                          P_("First Child"),
6403                          P_("The actor's first child"),
6404                          CLUTTER_TYPE_ACTOR,
6405                          CLUTTER_PARAM_READABLE);
6406
6407   /**
6408    * ClutterActor:last-child:
6409    *
6410    * The actor's last child.
6411    *
6412    * Since: 1.10
6413    */
6414   obj_props[PROP_LAST_CHILD] =
6415     g_param_spec_object ("last-child",
6416                          P_("Last Child"),
6417                          P_("The actor's last child"),
6418                          CLUTTER_TYPE_ACTOR,
6419                          CLUTTER_PARAM_READABLE);
6420
6421   /**
6422    * ClutterActor:content:
6423    *
6424    * The #ClutterContent implementation that controls the content
6425    * of the actor.
6426    *
6427    * Since: 1.10
6428    */
6429   obj_props[PROP_CONTENT] =
6430     g_param_spec_object ("content",
6431                          P_("Content"),
6432                          P_("Delegate object for painting the actor's content"),
6433                          CLUTTER_TYPE_CONTENT,
6434                          CLUTTER_PARAM_READWRITE);
6435
6436   /**
6437    * ClutterActor:content-gravity:
6438    *
6439    * The alignment that should be honoured by the #ClutterContent
6440    * set with the #ClutterActor:content property.
6441    *
6442    * Changing the value of this property will change the bounding box of
6443    * the content; you can use the #ClutterActor:content-box property to
6444    * get the position and size of the content within the actor's
6445    * allocation.
6446    *
6447    * This property is meaningful only for #ClutterContent implementations
6448    * that have a preferred size, and if the preferred size is smaller than
6449    * the actor's allocation.
6450    *
6451    * The #ClutterActor:content-gravity property is animatable.
6452    *
6453    * Since: 1.10
6454    */
6455   obj_props[PROP_CONTENT_GRAVITY] =
6456     g_param_spec_enum ("content-gravity",
6457                        P_("Content Gravity"),
6458                        P_("Alignment of the actor's content"),
6459                        CLUTTER_TYPE_CONTENT_GRAVITY,
6460                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6461                        CLUTTER_PARAM_READWRITE);
6462
6463   /**
6464    * ClutterActor:content-box:
6465    *
6466    * The bounding box for the #ClutterContent used by the actor.
6467    *
6468    * The value of this property is controlled by the #ClutterActor:allocation
6469    * and #ClutterActor:content-gravity properties of #ClutterActor.
6470    *
6471    * The bounding box for the content is guaranteed to never exceed the
6472    * allocation's of the actor.
6473    *
6474    * Since: 1.10
6475    */
6476   obj_props[PROP_CONTENT_BOX] =
6477     g_param_spec_boxed ("content-box",
6478                         P_("Content Box"),
6479                         P_("The bounding box of the actor's content"),
6480                         CLUTTER_TYPE_ACTOR_BOX,
6481                         G_PARAM_READABLE |
6482                         G_PARAM_STATIC_STRINGS |
6483                         CLUTTER_PARAM_ANIMATABLE);
6484
6485   obj_props[PROP_MINIFICATION_FILTER] =
6486     g_param_spec_enum ("minification-filter",
6487                        P_("Minification Filter"),
6488                        P_("The filter used when reducing the size of the content"),
6489                        CLUTTER_TYPE_SCALING_FILTER,
6490                        CLUTTER_SCALING_FILTER_LINEAR,
6491                        CLUTTER_PARAM_READWRITE);
6492
6493   obj_props[PROP_MAGNIFICATION_FILTER] =
6494     g_param_spec_enum ("magnification-filter",
6495                        P_("Magnification Filter"),
6496                        P_("The filter used when increasing the size of the content"),
6497                        CLUTTER_TYPE_SCALING_FILTER,
6498                        CLUTTER_SCALING_FILTER_LINEAR,
6499                        CLUTTER_PARAM_READWRITE);
6500
6501   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6502
6503   /**
6504    * ClutterActor::destroy:
6505    * @actor: the #ClutterActor which emitted the signal
6506    *
6507    * The ::destroy signal notifies that all references held on the
6508    * actor which emitted it should be released.
6509    *
6510    * The ::destroy signal should be used by all holders of a reference
6511    * on @actor.
6512    *
6513    * This signal might result in the finalization of the #ClutterActor
6514    * if all references are released.
6515    *
6516    * Composite actors and actors implementing the #ClutterContainer
6517    * interface should override the default implementation of the
6518    * class handler of this signal and call clutter_actor_destroy() on
6519    * their children. When overriding the default class handler, it is
6520    * required to chain up to the parent's implementation.
6521    *
6522    * Since: 0.2
6523    */
6524   actor_signals[DESTROY] =
6525     g_signal_new (I_("destroy"),
6526                   G_TYPE_FROM_CLASS (object_class),
6527                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6528                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6529                   NULL, NULL,
6530                   _clutter_marshal_VOID__VOID,
6531                   G_TYPE_NONE, 0);
6532   /**
6533    * ClutterActor::show:
6534    * @actor: the object which received the signal
6535    *
6536    * The ::show signal is emitted when an actor is visible and
6537    * rendered on the stage.
6538    *
6539    * Since: 0.2
6540    */
6541   actor_signals[SHOW] =
6542     g_signal_new (I_("show"),
6543                   G_TYPE_FROM_CLASS (object_class),
6544                   G_SIGNAL_RUN_FIRST,
6545                   G_STRUCT_OFFSET (ClutterActorClass, show),
6546                   NULL, NULL,
6547                   _clutter_marshal_VOID__VOID,
6548                   G_TYPE_NONE, 0);
6549   /**
6550    * ClutterActor::hide:
6551    * @actor: the object which received the signal
6552    *
6553    * The ::hide signal is emitted when an actor is no longer rendered
6554    * on the stage.
6555    *
6556    * Since: 0.2
6557    */
6558   actor_signals[HIDE] =
6559     g_signal_new (I_("hide"),
6560                   G_TYPE_FROM_CLASS (object_class),
6561                   G_SIGNAL_RUN_FIRST,
6562                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6563                   NULL, NULL,
6564                   _clutter_marshal_VOID__VOID,
6565                   G_TYPE_NONE, 0);
6566   /**
6567    * ClutterActor::parent-set:
6568    * @actor: the object which received the signal
6569    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6570    *
6571    * This signal is emitted when the parent of the actor changes.
6572    *
6573    * Since: 0.2
6574    */
6575   actor_signals[PARENT_SET] =
6576     g_signal_new (I_("parent-set"),
6577                   G_TYPE_FROM_CLASS (object_class),
6578                   G_SIGNAL_RUN_LAST,
6579                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6580                   NULL, NULL,
6581                   _clutter_marshal_VOID__OBJECT,
6582                   G_TYPE_NONE, 1,
6583                   CLUTTER_TYPE_ACTOR);
6584
6585   /**
6586    * ClutterActor::queue-redraw:
6587    * @actor: the actor we're bubbling the redraw request through
6588    * @origin: the actor which initiated the redraw request
6589    *
6590    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6591    * is called on @origin.
6592    *
6593    * The default implementation for #ClutterActor chains up to the
6594    * parent actor and queues a redraw on the parent, thus "bubbling"
6595    * the redraw queue up through the actor graph. The default
6596    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6597    * in a main loop idle handler.
6598    *
6599    * Note that the @origin actor may be the stage, or a container; it
6600    * does not have to be a leaf node in the actor graph.
6601    *
6602    * Toolkits embedding a #ClutterStage which require a redraw and
6603    * relayout cycle can stop the emission of this signal using the
6604    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6605    * themselves, like:
6606    *
6607    * |[
6608    *   static void
6609    *   on_redraw_complete (gpointer data)
6610    *   {
6611    *     ClutterStage *stage = data;
6612    *
6613    *     /&ast; execute the Clutter drawing pipeline &ast;/
6614    *     clutter_stage_ensure_redraw (stage);
6615    *   }
6616    *
6617    *   static void
6618    *   on_stage_queue_redraw (ClutterStage *stage)
6619    *   {
6620    *     /&ast; this prevents the default handler to run &ast;/
6621    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6622    *
6623    *     /&ast; queue a redraw with the host toolkit and call
6624    *      &ast; a function when the redraw has been completed
6625    *      &ast;/
6626    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6627    *   }
6628    * ]|
6629    *
6630    * <note><para>This signal is emitted before the Clutter paint
6631    * pipeline is executed. If you want to know when the pipeline has
6632    * been completed you should connect to the ::paint signal on the
6633    * Stage with g_signal_connect_after().</para></note>
6634    *
6635    * Since: 1.0
6636    */
6637   actor_signals[QUEUE_REDRAW] =
6638     g_signal_new (I_("queue-redraw"),
6639                   G_TYPE_FROM_CLASS (object_class),
6640                   G_SIGNAL_RUN_LAST |
6641                   G_SIGNAL_NO_HOOKS,
6642                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6643                   NULL, NULL,
6644                   _clutter_marshal_VOID__OBJECT,
6645                   G_TYPE_NONE, 1,
6646                   CLUTTER_TYPE_ACTOR);
6647
6648   /**
6649    * ClutterActor::queue-relayout
6650    * @actor: the actor being queued for relayout
6651    *
6652    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6653    * is called on an actor.
6654    *
6655    * The default implementation for #ClutterActor chains up to the
6656    * parent actor and queues a relayout on the parent, thus "bubbling"
6657    * the relayout queue up through the actor graph.
6658    *
6659    * The main purpose of this signal is to allow relayout to be propagated
6660    * properly in the procense of #ClutterClone actors. Applications will
6661    * not normally need to connect to this signal.
6662    *
6663    * Since: 1.2
6664    */
6665   actor_signals[QUEUE_RELAYOUT] =
6666     g_signal_new (I_("queue-relayout"),
6667                   G_TYPE_FROM_CLASS (object_class),
6668                   G_SIGNAL_RUN_LAST |
6669                   G_SIGNAL_NO_HOOKS,
6670                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6671                   NULL, NULL,
6672                   _clutter_marshal_VOID__VOID,
6673                   G_TYPE_NONE, 0);
6674
6675   /**
6676    * ClutterActor::event:
6677    * @actor: the actor which received the event
6678    * @event: a #ClutterEvent
6679    *
6680    * The ::event signal is emitted each time an event is received
6681    * by the @actor. This signal will be emitted on every actor,
6682    * following the hierarchy chain, until it reaches the top-level
6683    * container (the #ClutterStage).
6684    *
6685    * Return value: %TRUE if the event has been handled by the actor,
6686    *   or %FALSE to continue the emission.
6687    *
6688    * Since: 0.6
6689    */
6690   actor_signals[EVENT] =
6691     g_signal_new (I_("event"),
6692                   G_TYPE_FROM_CLASS (object_class),
6693                   G_SIGNAL_RUN_LAST,
6694                   G_STRUCT_OFFSET (ClutterActorClass, event),
6695                   _clutter_boolean_handled_accumulator, NULL,
6696                   _clutter_marshal_BOOLEAN__BOXED,
6697                   G_TYPE_BOOLEAN, 1,
6698                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6699   /**
6700    * ClutterActor::button-press-event:
6701    * @actor: the actor which received the event
6702    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6703    *
6704    * The ::button-press-event signal is emitted each time a mouse button
6705    * is pressed on @actor.
6706    *
6707    * Return value: %TRUE if the event has been handled by the actor,
6708    *   or %FALSE to continue the emission.
6709    *
6710    * Since: 0.6
6711    */
6712   actor_signals[BUTTON_PRESS_EVENT] =
6713     g_signal_new (I_("button-press-event"),
6714                   G_TYPE_FROM_CLASS (object_class),
6715                   G_SIGNAL_RUN_LAST,
6716                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6717                   _clutter_boolean_handled_accumulator, NULL,
6718                   _clutter_marshal_BOOLEAN__BOXED,
6719                   G_TYPE_BOOLEAN, 1,
6720                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6721   /**
6722    * ClutterActor::button-release-event:
6723    * @actor: the actor which received the event
6724    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6725    *
6726    * The ::button-release-event signal is emitted each time a mouse button
6727    * is released on @actor.
6728    *
6729    * Return value: %TRUE if the event has been handled by the actor,
6730    *   or %FALSE to continue the emission.
6731    *
6732    * Since: 0.6
6733    */
6734   actor_signals[BUTTON_RELEASE_EVENT] =
6735     g_signal_new (I_("button-release-event"),
6736                   G_TYPE_FROM_CLASS (object_class),
6737                   G_SIGNAL_RUN_LAST,
6738                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6739                   _clutter_boolean_handled_accumulator, NULL,
6740                   _clutter_marshal_BOOLEAN__BOXED,
6741                   G_TYPE_BOOLEAN, 1,
6742                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6743   /**
6744    * ClutterActor::scroll-event:
6745    * @actor: the actor which received the event
6746    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6747    *
6748    * The ::scroll-event signal is emitted each time the mouse is
6749    * scrolled on @actor
6750    *
6751    * Return value: %TRUE if the event has been handled by the actor,
6752    *   or %FALSE to continue the emission.
6753    *
6754    * Since: 0.6
6755    */
6756   actor_signals[SCROLL_EVENT] =
6757     g_signal_new (I_("scroll-event"),
6758                   G_TYPE_FROM_CLASS (object_class),
6759                   G_SIGNAL_RUN_LAST,
6760                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6761                   _clutter_boolean_handled_accumulator, NULL,
6762                   _clutter_marshal_BOOLEAN__BOXED,
6763                   G_TYPE_BOOLEAN, 1,
6764                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6765   /**
6766    * ClutterActor::key-press-event:
6767    * @actor: the actor which received the event
6768    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6769    *
6770    * The ::key-press-event signal is emitted each time a keyboard button
6771    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6772    *
6773    * Return value: %TRUE if the event has been handled by the actor,
6774    *   or %FALSE to continue the emission.
6775    *
6776    * Since: 0.6
6777    */
6778   actor_signals[KEY_PRESS_EVENT] =
6779     g_signal_new (I_("key-press-event"),
6780                   G_TYPE_FROM_CLASS (object_class),
6781                   G_SIGNAL_RUN_LAST,
6782                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6783                   _clutter_boolean_handled_accumulator, NULL,
6784                   _clutter_marshal_BOOLEAN__BOXED,
6785                   G_TYPE_BOOLEAN, 1,
6786                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6787   /**
6788    * ClutterActor::key-release-event:
6789    * @actor: the actor which received the event
6790    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6791    *
6792    * The ::key-release-event signal is emitted each time a keyboard button
6793    * is released while @actor has key focus (see
6794    * clutter_stage_set_key_focus()).
6795    *
6796    * Return value: %TRUE if the event has been handled by the actor,
6797    *   or %FALSE to continue the emission.
6798    *
6799    * Since: 0.6
6800    */
6801   actor_signals[KEY_RELEASE_EVENT] =
6802     g_signal_new (I_("key-release-event"),
6803                   G_TYPE_FROM_CLASS (object_class),
6804                   G_SIGNAL_RUN_LAST,
6805                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6806                   _clutter_boolean_handled_accumulator, NULL,
6807                   _clutter_marshal_BOOLEAN__BOXED,
6808                   G_TYPE_BOOLEAN, 1,
6809                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6810   /**
6811    * ClutterActor::motion-event:
6812    * @actor: the actor which received the event
6813    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6814    *
6815    * The ::motion-event signal is emitted each time the mouse pointer is
6816    * moved over @actor.
6817    *
6818    * Return value: %TRUE if the event has been handled by the actor,
6819    *   or %FALSE to continue the emission.
6820    *
6821    * Since: 0.6
6822    */
6823   actor_signals[MOTION_EVENT] =
6824     g_signal_new (I_("motion-event"),
6825                   G_TYPE_FROM_CLASS (object_class),
6826                   G_SIGNAL_RUN_LAST,
6827                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6828                   _clutter_boolean_handled_accumulator, NULL,
6829                   _clutter_marshal_BOOLEAN__BOXED,
6830                   G_TYPE_BOOLEAN, 1,
6831                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6832
6833   /**
6834    * ClutterActor::key-focus-in:
6835    * @actor: the actor which now has key focus
6836    *
6837    * The ::key-focus-in signal is emitted when @actor receives key focus.
6838    *
6839    * Since: 0.6
6840    */
6841   actor_signals[KEY_FOCUS_IN] =
6842     g_signal_new (I_("key-focus-in"),
6843                   G_TYPE_FROM_CLASS (object_class),
6844                   G_SIGNAL_RUN_LAST,
6845                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6846                   NULL, NULL,
6847                   _clutter_marshal_VOID__VOID,
6848                   G_TYPE_NONE, 0);
6849
6850   /**
6851    * ClutterActor::key-focus-out:
6852    * @actor: the actor which now has key focus
6853    *
6854    * The ::key-focus-out signal is emitted when @actor loses key focus.
6855    *
6856    * Since: 0.6
6857    */
6858   actor_signals[KEY_FOCUS_OUT] =
6859     g_signal_new (I_("key-focus-out"),
6860                   G_TYPE_FROM_CLASS (object_class),
6861                   G_SIGNAL_RUN_LAST,
6862                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6863                   NULL, NULL,
6864                   _clutter_marshal_VOID__VOID,
6865                   G_TYPE_NONE, 0);
6866
6867   /**
6868    * ClutterActor::enter-event:
6869    * @actor: the actor which the pointer has entered.
6870    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6871    *
6872    * The ::enter-event signal is emitted when the pointer enters the @actor
6873    *
6874    * Return value: %TRUE if the event has been handled by the actor,
6875    *   or %FALSE to continue the emission.
6876    *
6877    * Since: 0.6
6878    */
6879   actor_signals[ENTER_EVENT] =
6880     g_signal_new (I_("enter-event"),
6881                   G_TYPE_FROM_CLASS (object_class),
6882                   G_SIGNAL_RUN_LAST,
6883                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6884                   _clutter_boolean_handled_accumulator, NULL,
6885                   _clutter_marshal_BOOLEAN__BOXED,
6886                   G_TYPE_BOOLEAN, 1,
6887                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6888
6889   /**
6890    * ClutterActor::leave-event:
6891    * @actor: the actor which the pointer has left
6892    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6893    *
6894    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6895    *
6896    * Return value: %TRUE if the event has been handled by the actor,
6897    *   or %FALSE to continue the emission.
6898    *
6899    * Since: 0.6
6900    */
6901   actor_signals[LEAVE_EVENT] =
6902     g_signal_new (I_("leave-event"),
6903                   G_TYPE_FROM_CLASS (object_class),
6904                   G_SIGNAL_RUN_LAST,
6905                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6906                   _clutter_boolean_handled_accumulator, NULL,
6907                   _clutter_marshal_BOOLEAN__BOXED,
6908                   G_TYPE_BOOLEAN, 1,
6909                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6910
6911   /**
6912    * ClutterActor::captured-event:
6913    * @actor: the actor which received the signal
6914    * @event: a #ClutterEvent
6915    *
6916    * The ::captured-event signal is emitted when an event is captured
6917    * by Clutter. This signal will be emitted starting from the top-level
6918    * container (the #ClutterStage) to the actor which received the event
6919    * going down the hierarchy. This signal can be used to intercept every
6920    * event before the specialized events (like
6921    * ClutterActor::button-press-event or ::key-released-event) are
6922    * emitted.
6923    *
6924    * Return value: %TRUE if the event has been handled by the actor,
6925    *   or %FALSE to continue the emission.
6926    *
6927    * Since: 0.6
6928    */
6929   actor_signals[CAPTURED_EVENT] =
6930     g_signal_new (I_("captured-event"),
6931                   G_TYPE_FROM_CLASS (object_class),
6932                   G_SIGNAL_RUN_LAST,
6933                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6934                   _clutter_boolean_handled_accumulator, NULL,
6935                   _clutter_marshal_BOOLEAN__BOXED,
6936                   G_TYPE_BOOLEAN, 1,
6937                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6938
6939   /**
6940    * ClutterActor::paint:
6941    * @actor: the #ClutterActor that received the signal
6942    *
6943    * The ::paint signal is emitted each time an actor is being painted.
6944    *
6945    * Subclasses of #ClutterActor should override the class signal handler
6946    * and paint themselves in that function.
6947    *
6948    * It is possible to connect a handler to the ::paint signal in order
6949    * to set up some custom aspect of a paint.
6950    *
6951    * Since: 0.8
6952    */
6953   actor_signals[PAINT] =
6954     g_signal_new (I_("paint"),
6955                   G_TYPE_FROM_CLASS (object_class),
6956                   G_SIGNAL_RUN_LAST |
6957                   G_SIGNAL_NO_HOOKS,
6958                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6959                   NULL, NULL,
6960                   _clutter_marshal_VOID__VOID,
6961                   G_TYPE_NONE, 0);
6962   /**
6963    * ClutterActor::realize:
6964    * @actor: the #ClutterActor that received the signal
6965    *
6966    * The ::realize signal is emitted each time an actor is being
6967    * realized.
6968    *
6969    * Since: 0.8
6970    */
6971   actor_signals[REALIZE] =
6972     g_signal_new (I_("realize"),
6973                   G_TYPE_FROM_CLASS (object_class),
6974                   G_SIGNAL_RUN_LAST,
6975                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6976                   NULL, NULL,
6977                   _clutter_marshal_VOID__VOID,
6978                   G_TYPE_NONE, 0);
6979   /**
6980    * ClutterActor::unrealize:
6981    * @actor: the #ClutterActor that received the signal
6982    *
6983    * The ::unrealize signal is emitted each time an actor is being
6984    * unrealized.
6985    *
6986    * Since: 0.8
6987    */
6988   actor_signals[UNREALIZE] =
6989     g_signal_new (I_("unrealize"),
6990                   G_TYPE_FROM_CLASS (object_class),
6991                   G_SIGNAL_RUN_LAST,
6992                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6993                   NULL, NULL,
6994                   _clutter_marshal_VOID__VOID,
6995                   G_TYPE_NONE, 0);
6996
6997   /**
6998    * ClutterActor::pick:
6999    * @actor: the #ClutterActor that received the signal
7000    * @color: the #ClutterColor to be used when picking
7001    *
7002    * The ::pick signal is emitted each time an actor is being painted
7003    * in "pick mode". The pick mode is used to identify the actor during
7004    * the event handling phase, or by clutter_stage_get_actor_at_pos().
7005    * The actor should paint its shape using the passed @pick_color.
7006    *
7007    * Subclasses of #ClutterActor should override the class signal handler
7008    * and paint themselves in that function.
7009    *
7010    * It is possible to connect a handler to the ::pick signal in order
7011    * to set up some custom aspect of a paint in pick mode.
7012    *
7013    * Since: 1.0
7014    */
7015   actor_signals[PICK] =
7016     g_signal_new (I_("pick"),
7017                   G_TYPE_FROM_CLASS (object_class),
7018                   G_SIGNAL_RUN_LAST,
7019                   G_STRUCT_OFFSET (ClutterActorClass, pick),
7020                   NULL, NULL,
7021                   _clutter_marshal_VOID__BOXED,
7022                   G_TYPE_NONE, 1,
7023                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7024
7025   /**
7026    * ClutterActor::allocation-changed:
7027    * @actor: the #ClutterActor that emitted the signal
7028    * @box: a #ClutterActorBox with the new allocation
7029    * @flags: #ClutterAllocationFlags for the allocation
7030    *
7031    * The ::allocation-changed signal is emitted when the
7032    * #ClutterActor:allocation property changes. Usually, application
7033    * code should just use the notifications for the :allocation property
7034    * but if you want to track the allocation flags as well, for instance
7035    * to know whether the absolute origin of @actor changed, then you might
7036    * want use this signal instead.
7037    *
7038    * Since: 1.0
7039    */
7040   actor_signals[ALLOCATION_CHANGED] =
7041     g_signal_new (I_("allocation-changed"),
7042                   G_TYPE_FROM_CLASS (object_class),
7043                   G_SIGNAL_RUN_LAST,
7044                   0,
7045                   NULL, NULL,
7046                   _clutter_marshal_VOID__BOXED_FLAGS,
7047                   G_TYPE_NONE, 2,
7048                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7049                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7050
7051   /**
7052    * ClutterActor::transitions-completed:
7053    * @actor: a #ClutterActor
7054    *
7055    * The ::transitions-completed signal is emitted once all transitions
7056    * involving @actor are complete.
7057    *
7058    * Since: 1.10
7059    */
7060   actor_signals[TRANSITIONS_COMPLETED] =
7061     g_signal_new (I_("transitions-completed"),
7062                   G_TYPE_FROM_CLASS (object_class),
7063                   G_SIGNAL_RUN_LAST,
7064                   0,
7065                   NULL, NULL,
7066                   _clutter_marshal_VOID__VOID,
7067                   G_TYPE_NONE, 0);
7068 }
7069
7070 static void
7071 clutter_actor_init (ClutterActor *self)
7072 {
7073   ClutterActorPrivate *priv;
7074
7075   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7076
7077   priv->id = _clutter_context_acquire_id (self);
7078   priv->pick_id = -1;
7079
7080   priv->opacity = 0xff;
7081   priv->show_on_set_parent = TRUE;
7082
7083   priv->needs_width_request = TRUE;
7084   priv->needs_height_request = TRUE;
7085   priv->needs_allocation = TRUE;
7086
7087   priv->cached_width_age = 1;
7088   priv->cached_height_age = 1;
7089
7090   priv->opacity_override = -1;
7091   priv->enable_model_view_transform = TRUE;
7092
7093   /* Initialize an empty paint volume to start with */
7094   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7095   priv->last_paint_volume_valid = TRUE;
7096
7097   priv->transform_valid = FALSE;
7098
7099   /* the default is to stretch the content, to match the
7100    * current behaviour of basically all actors. also, it's
7101    * the easiest thing to compute.
7102    */
7103   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7104   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7105   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7106 }
7107
7108 /**
7109  * clutter_actor_new:
7110  *
7111  * Creates a new #ClutterActor.
7112  *
7113  * A newly created actor has a floating reference, which will be sunk
7114  * when it is added to another actor.
7115  *
7116  * Return value: (transfer full): the newly created #ClutterActor
7117  *
7118  * Since: 1.10
7119  */
7120 ClutterActor *
7121 clutter_actor_new (void)
7122 {
7123   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7124 }
7125
7126 /**
7127  * clutter_actor_destroy:
7128  * @self: a #ClutterActor
7129  *
7130  * Destroys an actor.  When an actor is destroyed, it will break any
7131  * references it holds to other objects.  If the actor is inside a
7132  * container, the actor will be removed.
7133  *
7134  * When you destroy a container, its children will be destroyed as well.
7135  *
7136  * Note: you cannot destroy the #ClutterStage returned by
7137  * clutter_stage_get_default().
7138  */
7139 void
7140 clutter_actor_destroy (ClutterActor *self)
7141 {
7142   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7143
7144   g_object_ref (self);
7145
7146   /* avoid recursion while destroying */
7147   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7148     {
7149       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7150
7151       g_object_run_dispose (G_OBJECT (self));
7152
7153       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7154     }
7155
7156   g_object_unref (self);
7157 }
7158
7159 void
7160 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7161                                     ClutterPaintVolume *clip)
7162 {
7163   ClutterActorPrivate *priv = self->priv;
7164   ClutterPaintVolume *pv;
7165   gboolean clipped;
7166
7167   /* Remove queue entry early in the process, otherwise a new
7168      queue_redraw() during signal handling could put back this
7169      object in the stage redraw list (but the entry is freed as
7170      soon as we return from this function, causing a segfault
7171      later)
7172   */
7173   priv->queue_redraw_entry = NULL;
7174
7175   /* If we've been explicitly passed a clip volume then there's
7176    * nothing more to calculate, but otherwise the only thing we know
7177    * is that the change is constrained to the given actor.
7178    *
7179    * The idea is that if we know the paint volume for where the actor
7180    * was last drawn (in eye coordinates) and we also have the paint
7181    * volume for where it will be drawn next (in actor coordinates)
7182    * then if we queue a redraw for both these volumes that will cover
7183    * everything that needs to be redrawn to clear the old view and
7184    * show the latest view of the actor.
7185    *
7186    * Don't clip this redraw if we don't know what position we had for
7187    * the previous redraw since we don't know where to set the clip so
7188    * it will clear the actor as it is currently.
7189    */
7190   if (clip)
7191     {
7192       _clutter_actor_set_queue_redraw_clip (self, clip);
7193       clipped = TRUE;
7194     }
7195   else if (G_LIKELY (priv->last_paint_volume_valid))
7196     {
7197       pv = _clutter_actor_get_paint_volume_mutable (self);
7198       if (pv)
7199         {
7200           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7201
7202           /* make sure we redraw the actors old position... */
7203           _clutter_actor_set_queue_redraw_clip (stage,
7204                                                 &priv->last_paint_volume);
7205           _clutter_actor_signal_queue_redraw (stage, stage);
7206           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7207
7208           /* XXX: Ideally the redraw signal would take a clip volume
7209            * argument, but that would be an ABI break. Until we can
7210            * break the ABI we pass the argument out-of-band
7211            */
7212
7213           /* setup the clip for the actors new position... */
7214           _clutter_actor_set_queue_redraw_clip (self, pv);
7215           clipped = TRUE;
7216         }
7217       else
7218         clipped = FALSE;
7219     }
7220   else
7221     clipped = FALSE;
7222
7223   _clutter_actor_signal_queue_redraw (self, self);
7224
7225   /* Just in case anyone is manually firing redraw signals without
7226    * using the public queue_redraw() API we are careful to ensure that
7227    * our out-of-band clip member is cleared before returning...
7228    *
7229    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7230    */
7231   if (G_LIKELY (clipped))
7232     _clutter_actor_set_queue_redraw_clip (self, NULL);
7233 }
7234
7235 static void
7236 _clutter_actor_get_allocation_clip (ClutterActor *self,
7237                                     ClutterActorBox *clip)
7238 {
7239   ClutterActorBox allocation;
7240
7241   /* XXX: we don't care if we get an out of date allocation here
7242    * because clutter_actor_queue_redraw_with_clip knows to ignore
7243    * the clip if the actor's allocation is invalid.
7244    *
7245    * This is noted because clutter_actor_get_allocation_box does some
7246    * unnecessary work to support buggy code with a comment suggesting
7247    * that it could be changed later which would be good for this use
7248    * case!
7249    */
7250   clutter_actor_get_allocation_box (self, &allocation);
7251
7252   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7253    * actor's own coordinate space but the allocation is in parent
7254    * coordinates */
7255   clip->x1 = 0;
7256   clip->y1 = 0;
7257   clip->x2 = allocation.x2 - allocation.x1;
7258   clip->y2 = allocation.y2 - allocation.y1;
7259 }
7260
7261 void
7262 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7263                                   ClutterRedrawFlags  flags,
7264                                   ClutterPaintVolume *volume,
7265                                   ClutterEffect      *effect)
7266 {
7267   ClutterActorPrivate *priv = self->priv;
7268   ClutterPaintVolume allocation_pv;
7269   ClutterPaintVolume *pv;
7270   gboolean should_free_pv;
7271   ClutterActor *stage;
7272
7273   /* Here's an outline of the actor queue redraw mechanism:
7274    *
7275    * The process starts in one of the following two functions which
7276    * are wrappers for this function:
7277    * clutter_actor_queue_redraw
7278    * _clutter_actor_queue_redraw_with_clip
7279    *
7280    * additionally, an effect can queue a redraw by wrapping this
7281    * function in clutter_effect_queue_rerun
7282    *
7283    * This functions queues an entry in a list associated with the
7284    * stage which is a list of actors that queued a redraw while
7285    * updating the timelines, performing layouting and processing other
7286    * mainloop sources before the next paint starts.
7287    *
7288    * We aim to minimize the processing done at this point because
7289    * there is a good chance other events will happen while updating
7290    * the scenegraph that would invalidate any expensive work we might
7291    * otherwise try to do here. For example we don't try and resolve
7292    * the screen space bounding box of an actor at this stage so as to
7293    * minimize how much of the screen redraw because it's possible
7294    * something else will happen which will force a full redraw anyway.
7295    *
7296    * When all updates are complete and we come to paint the stage then
7297    * we iterate this list and actually emit the "queue-redraw" signals
7298    * for each of the listed actors which will bubble up to the stage
7299    * for each actor and at that point we will transform the actors
7300    * paint volume into screen coordinates to determine the clip region
7301    * for what needs to be redrawn in the next paint.
7302    *
7303    * Besides minimizing redundant work another reason for this
7304    * deferred design is that it's more likely we will be able to
7305    * determine the paint volume of an actor once we've finished
7306    * updating the scenegraph because its allocation should be up to
7307    * date. NB: If we can't determine an actors paint volume then we
7308    * can't automatically queue a clipped redraw which can make a big
7309    * difference to performance.
7310    *
7311    * So the control flow goes like this:
7312    * One of clutter_actor_queue_redraw,
7313    *        _clutter_actor_queue_redraw_with_clip
7314    *     or clutter_effect_queue_rerun
7315    *
7316    * then control moves to:
7317    *   _clutter_stage_queue_actor_redraw
7318    *
7319    * later during _clutter_stage_do_update, once relayouting is done
7320    * and the scenegraph has been updated we will call:
7321    * _clutter_stage_finish_queue_redraws
7322    *
7323    * _clutter_stage_finish_queue_redraws will call
7324    * _clutter_actor_finish_queue_redraw for each listed actor.
7325    * Note: actors *are* allowed to queue further redraws during this
7326    * process (considering clone actors or texture_new_from_actor which
7327    * respond to their source queueing a redraw by queuing a redraw
7328    * themselves). We repeat the process until the list is empty.
7329    *
7330    * This will result in the "queue-redraw" signal being fired for
7331    * each actor which will pass control to the default signal handler:
7332    * clutter_actor_real_queue_redraw
7333    *
7334    * This will bubble up to the stages handler:
7335    * clutter_stage_real_queue_redraw
7336    *
7337    * clutter_stage_real_queue_redraw will transform the actors paint
7338    * volume into screen space and add it as a clip region for the next
7339    * paint.
7340    */
7341
7342   /* ignore queueing a redraw for actors being destroyed */
7343   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7344     return;
7345
7346   stage = _clutter_actor_get_stage_internal (self);
7347
7348   /* Ignore queueing a redraw for actors not descended from a stage */
7349   if (stage == NULL)
7350     return;
7351
7352   /* ignore queueing a redraw on stages that are being destroyed */
7353   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7354     return;
7355
7356   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7357     {
7358       ClutterActorBox allocation_clip;
7359       ClutterVertex origin;
7360
7361       /* If the actor doesn't have a valid allocation then we will
7362        * queue a full stage redraw. */
7363       if (priv->needs_allocation)
7364         {
7365           /* NB: NULL denotes an undefined clip which will result in a
7366            * full redraw... */
7367           _clutter_actor_set_queue_redraw_clip (self, NULL);
7368           _clutter_actor_signal_queue_redraw (self, self);
7369           return;
7370         }
7371
7372       _clutter_paint_volume_init_static (&allocation_pv, self);
7373       pv = &allocation_pv;
7374
7375       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7376
7377       origin.x = allocation_clip.x1;
7378       origin.y = allocation_clip.y1;
7379       origin.z = 0;
7380       clutter_paint_volume_set_origin (pv, &origin);
7381       clutter_paint_volume_set_width (pv,
7382                                       allocation_clip.x2 - allocation_clip.x1);
7383       clutter_paint_volume_set_height (pv,
7384                                        allocation_clip.y2 -
7385                                        allocation_clip.y1);
7386       should_free_pv = TRUE;
7387     }
7388   else
7389     {
7390       pv = volume;
7391       should_free_pv = FALSE;
7392     }
7393
7394   self->priv->queue_redraw_entry =
7395     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7396                                        priv->queue_redraw_entry,
7397                                        self,
7398                                        pv);
7399
7400   if (should_free_pv)
7401     clutter_paint_volume_free (pv);
7402
7403   /* If this is the first redraw queued then we can directly use the
7404      effect parameter */
7405   if (!priv->is_dirty)
7406     priv->effect_to_redraw = effect;
7407   /* Otherwise we need to merge it with the existing effect parameter */
7408   else if (effect != NULL)
7409     {
7410       /* If there's already an effect then we need to use whichever is
7411          later in the chain of actors. Otherwise a full redraw has
7412          already been queued on the actor so we need to ignore the
7413          effect parameter */
7414       if (priv->effect_to_redraw != NULL)
7415         {
7416           if (priv->effects == NULL)
7417             g_warning ("Redraw queued with an effect that is "
7418                        "not applied to the actor");
7419           else
7420             {
7421               const GList *l;
7422
7423               for (l = _clutter_meta_group_peek_metas (priv->effects);
7424                    l != NULL;
7425                    l = l->next)
7426                 {
7427                   if (l->data == priv->effect_to_redraw ||
7428                       l->data == effect)
7429                     priv->effect_to_redraw = l->data;
7430                 }
7431             }
7432         }
7433     }
7434   else
7435     {
7436       /* If no effect is specified then we need to redraw the whole
7437          actor */
7438       priv->effect_to_redraw = NULL;
7439     }
7440
7441   priv->is_dirty = TRUE;
7442 }
7443
7444 /**
7445  * clutter_actor_queue_redraw:
7446  * @self: A #ClutterActor
7447  *
7448  * Queues up a redraw of an actor and any children. The redraw occurs
7449  * once the main loop becomes idle (after the current batch of events
7450  * has been processed, roughly).
7451  *
7452  * Applications rarely need to call this, as redraws are handled
7453  * automatically by modification functions.
7454  *
7455  * This function will not do anything if @self is not visible, or
7456  * if the actor is inside an invisible part of the scenegraph.
7457  *
7458  * Also be aware that painting is a NOP for actors with an opacity of
7459  * 0
7460  *
7461  * When you are implementing a custom actor you must queue a redraw
7462  * whenever some private state changes that will affect painting or
7463  * picking of your actor.
7464  */
7465 void
7466 clutter_actor_queue_redraw (ClutterActor *self)
7467 {
7468   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7469
7470   _clutter_actor_queue_redraw_full (self,
7471                                     0, /* flags */
7472                                     NULL, /* clip volume */
7473                                     NULL /* effect */);
7474 }
7475
7476 /*< private >
7477  * _clutter_actor_queue_redraw_with_clip:
7478  * @self: A #ClutterActor
7479  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7480  *   this queue redraw.
7481  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7482  *   redrawn or %NULL if you are just using a @flag to state your
7483  *   desired clipping.
7484  *
7485  * Queues up a clipped redraw of an actor and any children. The redraw
7486  * occurs once the main loop becomes idle (after the current batch of
7487  * events has been processed, roughly).
7488  *
7489  * If no flags are given the clip volume is defined by @volume
7490  * specified in actor coordinates and tells Clutter that only content
7491  * within this volume has been changed so Clutter can optionally
7492  * optimize the redraw.
7493  *
7494  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7495  * should be %NULL and this tells Clutter to use the actor's current
7496  * allocation as a clip box. This flag can only be used for 2D actors,
7497  * because any actor with depth may be projected outside its
7498  * allocation.
7499  *
7500  * Applications rarely need to call this, as redraws are handled
7501  * automatically by modification functions.
7502  *
7503  * This function will not do anything if @self is not visible, or if
7504  * the actor is inside an invisible part of the scenegraph.
7505  *
7506  * Also be aware that painting is a NOP for actors with an opacity of
7507  * 0
7508  *
7509  * When you are implementing a custom actor you must queue a redraw
7510  * whenever some private state changes that will affect painting or
7511  * picking of your actor.
7512  */
7513 void
7514 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7515                                        ClutterRedrawFlags  flags,
7516                                        ClutterPaintVolume *volume)
7517 {
7518   _clutter_actor_queue_redraw_full (self,
7519                                     flags, /* flags */
7520                                     volume, /* clip volume */
7521                                     NULL /* effect */);
7522 }
7523
7524 static void
7525 _clutter_actor_queue_only_relayout (ClutterActor *self)
7526 {
7527   ClutterActorPrivate *priv = self->priv;
7528
7529   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7530     return;
7531
7532   if (priv->needs_width_request &&
7533       priv->needs_height_request &&
7534       priv->needs_allocation)
7535     return; /* save some cpu cycles */
7536
7537 #if CLUTTER_ENABLE_DEBUG
7538   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7539     {
7540       g_warning ("The actor '%s' is currently inside an allocation "
7541                  "cycle; calling clutter_actor_queue_relayout() is "
7542                  "not recommended",
7543                  _clutter_actor_get_debug_name (self));
7544     }
7545 #endif /* CLUTTER_ENABLE_DEBUG */
7546
7547   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7548 }
7549
7550 /**
7551  * clutter_actor_queue_redraw_with_clip:
7552  * @self: a #ClutterActor
7553  * @clip: (allow-none): a rectangular clip region, or %NULL
7554  *
7555  * Queues a redraw on @self limited to a specific, actor-relative
7556  * rectangular area.
7557  *
7558  * If @clip is %NULL this function is equivalent to
7559  * clutter_actor_queue_redraw().
7560  *
7561  * Since: 1.10
7562  */
7563 void
7564 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7565                                       const cairo_rectangle_int_t *clip)
7566 {
7567   ClutterPaintVolume volume;
7568   ClutterVertex origin;
7569
7570   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7571
7572   if (clip == NULL)
7573     {
7574       clutter_actor_queue_redraw (self);
7575       return;
7576     }
7577
7578   _clutter_paint_volume_init_static (&volume, self);
7579
7580   origin.x = clip->x;
7581   origin.y = clip->y;
7582   origin.z = 0.0f;
7583
7584   clutter_paint_volume_set_origin (&volume, &origin);
7585   clutter_paint_volume_set_width (&volume, clip->width);
7586   clutter_paint_volume_set_height (&volume, clip->height);
7587
7588   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7589
7590   clutter_paint_volume_free (&volume);
7591 }
7592
7593 /**
7594  * clutter_actor_queue_relayout:
7595  * @self: A #ClutterActor
7596  *
7597  * Indicates that the actor's size request or other layout-affecting
7598  * properties may have changed. This function is used inside #ClutterActor
7599  * subclass implementations, not by applications directly.
7600  *
7601  * Queueing a new layout automatically queues a redraw as well.
7602  *
7603  * Since: 0.8
7604  */
7605 void
7606 clutter_actor_queue_relayout (ClutterActor *self)
7607 {
7608   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7609
7610   _clutter_actor_queue_only_relayout (self);
7611   clutter_actor_queue_redraw (self);
7612 }
7613
7614 /**
7615  * clutter_actor_get_preferred_size:
7616  * @self: a #ClutterActor
7617  * @min_width_p: (out) (allow-none): return location for the minimum
7618  *   width, or %NULL
7619  * @min_height_p: (out) (allow-none): return location for the minimum
7620  *   height, or %NULL
7621  * @natural_width_p: (out) (allow-none): return location for the natural
7622  *   width, or %NULL
7623  * @natural_height_p: (out) (allow-none): return location for the natural
7624  *   height, or %NULL
7625  *
7626  * Computes the preferred minimum and natural size of an actor, taking into
7627  * account the actor's geometry management (either height-for-width
7628  * or width-for-height).
7629  *
7630  * The width and height used to compute the preferred height and preferred
7631  * width are the actor's natural ones.
7632  *
7633  * If you need to control the height for the preferred width, or the width for
7634  * the preferred height, you should use clutter_actor_get_preferred_width()
7635  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7636  * geometry management using the #ClutterActor:request-mode property.
7637  *
7638  * Since: 0.8
7639  */
7640 void
7641 clutter_actor_get_preferred_size (ClutterActor *self,
7642                                   gfloat       *min_width_p,
7643                                   gfloat       *min_height_p,
7644                                   gfloat       *natural_width_p,
7645                                   gfloat       *natural_height_p)
7646 {
7647   ClutterActorPrivate *priv;
7648   gfloat min_width, min_height;
7649   gfloat natural_width, natural_height;
7650
7651   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7652
7653   priv = self->priv;
7654
7655   min_width = min_height = 0;
7656   natural_width = natural_height = 0;
7657
7658   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7659     {
7660       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7661       clutter_actor_get_preferred_width (self, -1,
7662                                          &min_width,
7663                                          &natural_width);
7664       clutter_actor_get_preferred_height (self, natural_width,
7665                                           &min_height,
7666                                           &natural_height);
7667     }
7668   else
7669     {
7670       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7671       clutter_actor_get_preferred_height (self, -1,
7672                                           &min_height,
7673                                           &natural_height);
7674       clutter_actor_get_preferred_width (self, natural_height,
7675                                          &min_width,
7676                                          &natural_width);
7677     }
7678
7679   if (min_width_p)
7680     *min_width_p = min_width;
7681
7682   if (min_height_p)
7683     *min_height_p = min_height;
7684
7685   if (natural_width_p)
7686     *natural_width_p = natural_width;
7687
7688   if (natural_height_p)
7689     *natural_height_p = natural_height;
7690 }
7691
7692 /*< private >
7693  * effective_align:
7694  * @align: a #ClutterActorAlign
7695  * @direction: a #ClutterTextDirection
7696  *
7697  * Retrieves the correct alignment depending on the text direction
7698  *
7699  * Return value: the effective alignment
7700  */
7701 static ClutterActorAlign
7702 effective_align (ClutterActorAlign    align,
7703                  ClutterTextDirection direction)
7704 {
7705   ClutterActorAlign res;
7706
7707   switch (align)
7708     {
7709     case CLUTTER_ACTOR_ALIGN_START:
7710       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7711           ? CLUTTER_ACTOR_ALIGN_END
7712           : CLUTTER_ACTOR_ALIGN_START;
7713       break;
7714
7715     case CLUTTER_ACTOR_ALIGN_END:
7716       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7717           ? CLUTTER_ACTOR_ALIGN_START
7718           : CLUTTER_ACTOR_ALIGN_END;
7719       break;
7720
7721     default:
7722       res = align;
7723       break;
7724     }
7725
7726   return res;
7727 }
7728
7729 static inline void
7730 adjust_for_margin (float  margin_start,
7731                    float  margin_end,
7732                    float *minimum_size,
7733                    float *natural_size,
7734                    float *allocated_start,
7735                    float *allocated_end)
7736 {
7737   *minimum_size -= (margin_start + margin_end);
7738   *natural_size -= (margin_start + margin_end);
7739   *allocated_start += margin_start;
7740   *allocated_end -= margin_end;
7741 }
7742
7743 static inline void
7744 adjust_for_alignment (ClutterActorAlign  alignment,
7745                       float              natural_size,
7746                       float             *allocated_start,
7747                       float             *allocated_end)
7748 {
7749   float allocated_size = *allocated_end - *allocated_start;
7750
7751   switch (alignment)
7752     {
7753     case CLUTTER_ACTOR_ALIGN_FILL:
7754       /* do nothing */
7755       break;
7756
7757     case CLUTTER_ACTOR_ALIGN_START:
7758       /* keep start */
7759       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7760       break;
7761
7762     case CLUTTER_ACTOR_ALIGN_END:
7763       if (allocated_size > natural_size)
7764         {
7765           *allocated_start += (allocated_size - natural_size);
7766           *allocated_end = *allocated_start + natural_size;
7767         }
7768       break;
7769
7770     case CLUTTER_ACTOR_ALIGN_CENTER:
7771       if (allocated_size > natural_size)
7772         {
7773           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7774           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7775         }
7776       break;
7777     }
7778 }
7779
7780 /*< private >
7781  * clutter_actor_adjust_width:
7782  * @self: a #ClutterActor
7783  * @minimum_width: (inout): the actor's preferred minimum width, which
7784  *   will be adjusted depending on the margin
7785  * @natural_width: (inout): the actor's preferred natural width, which
7786  *   will be adjusted depending on the margin
7787  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7788  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7789  *
7790  * Adjusts the preferred and allocated position and size of an actor,
7791  * depending on the margin and alignment properties.
7792  */
7793 static void
7794 clutter_actor_adjust_width (ClutterActor *self,
7795                             gfloat       *minimum_width,
7796                             gfloat       *natural_width,
7797                             gfloat       *adjusted_x1,
7798                             gfloat       *adjusted_x2)
7799 {
7800   ClutterTextDirection text_dir;
7801   const ClutterLayoutInfo *info;
7802
7803   info = _clutter_actor_get_layout_info_or_defaults (self);
7804   text_dir = clutter_actor_get_text_direction (self);
7805
7806   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7807
7808   /* this will tweak natural_width to remove the margin, so that
7809    * adjust_for_alignment() will use the correct size
7810    */
7811   adjust_for_margin (info->margin.left, info->margin.right,
7812                      minimum_width, natural_width,
7813                      adjusted_x1, adjusted_x2);
7814
7815   adjust_for_alignment (effective_align (info->x_align, text_dir),
7816                         *natural_width,
7817                         adjusted_x1, adjusted_x2);
7818 }
7819
7820 /*< private >
7821  * clutter_actor_adjust_height:
7822  * @self: a #ClutterActor
7823  * @minimum_height: (inout): the actor's preferred minimum height, which
7824  *   will be adjusted depending on the margin
7825  * @natural_height: (inout): the actor's preferred natural height, which
7826  *   will be adjusted depending on the margin
7827  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7828  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7829  *
7830  * Adjusts the preferred and allocated position and size of an actor,
7831  * depending on the margin and alignment properties.
7832  */
7833 static void
7834 clutter_actor_adjust_height (ClutterActor *self,
7835                              gfloat       *minimum_height,
7836                              gfloat       *natural_height,
7837                              gfloat       *adjusted_y1,
7838                              gfloat       *adjusted_y2)
7839 {
7840   const ClutterLayoutInfo *info;
7841
7842   info = _clutter_actor_get_layout_info_or_defaults (self);
7843
7844   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7845
7846   /* this will tweak natural_height to remove the margin, so that
7847    * adjust_for_alignment() will use the correct size
7848    */
7849   adjust_for_margin (info->margin.top, info->margin.bottom,
7850                      minimum_height, natural_height,
7851                      adjusted_y1,
7852                      adjusted_y2);
7853
7854   /* we don't use effective_align() here, because text direction
7855    * only affects the horizontal axis
7856    */
7857   adjust_for_alignment (info->y_align,
7858                         *natural_height,
7859                         adjusted_y1,
7860                         adjusted_y2);
7861
7862 }
7863
7864 /* looks for a cached size request for this for_size. If not
7865  * found, returns the oldest entry so it can be overwritten */
7866 static gboolean
7867 _clutter_actor_get_cached_size_request (gfloat         for_size,
7868                                         SizeRequest   *cached_size_requests,
7869                                         SizeRequest  **result)
7870 {
7871   guint i;
7872
7873   *result = &cached_size_requests[0];
7874
7875   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7876     {
7877       SizeRequest *sr;
7878
7879       sr = &cached_size_requests[i];
7880
7881       if (sr->age > 0 &&
7882           sr->for_size == for_size)
7883         {
7884           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7885           *result = sr;
7886           return TRUE;
7887         }
7888       else if (sr->age < (*result)->age)
7889         {
7890           *result = sr;
7891         }
7892     }
7893
7894   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7895
7896   return FALSE;
7897 }
7898
7899 /**
7900  * clutter_actor_get_preferred_width:
7901  * @self: A #ClutterActor
7902  * @for_height: available height when computing the preferred width,
7903  *   or a negative value to indicate that no height is defined
7904  * @min_width_p: (out) (allow-none): return location for minimum width,
7905  *   or %NULL
7906  * @natural_width_p: (out) (allow-none): return location for the natural
7907  *   width, or %NULL
7908  *
7909  * Computes the requested minimum and natural widths for an actor,
7910  * optionally depending on the specified height, or if they are
7911  * already computed, returns the cached values.
7912  *
7913  * An actor may not get its request - depending on the layout
7914  * manager that's in effect.
7915  *
7916  * A request should not incorporate the actor's scale or anchor point;
7917  * those transformations do not affect layout, only rendering.
7918  *
7919  * Since: 0.8
7920  */
7921 void
7922 clutter_actor_get_preferred_width (ClutterActor *self,
7923                                    gfloat        for_height,
7924                                    gfloat       *min_width_p,
7925                                    gfloat       *natural_width_p)
7926 {
7927   float request_min_width, request_natural_width;
7928   SizeRequest *cached_size_request;
7929   const ClutterLayoutInfo *info;
7930   ClutterActorPrivate *priv;
7931   gboolean found_in_cache;
7932
7933   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7934
7935   priv = self->priv;
7936
7937   info = _clutter_actor_get_layout_info_or_defaults (self);
7938
7939   /* we shortcircuit the case of a fixed size set using set_width() */
7940   if (priv->min_width_set && priv->natural_width_set)
7941     {
7942       if (min_width_p != NULL)
7943         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7944
7945       if (natural_width_p != NULL)
7946         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7947
7948       return;
7949     }
7950
7951   /* the remaining cases are:
7952    *
7953    *   - either min_width or natural_width have been set
7954    *   - neither min_width or natural_width have been set
7955    *
7956    * in both cases, we go through the cache (and through the actor in case
7957    * of cache misses) and determine the authoritative value depending on
7958    * the *_set flags.
7959    */
7960
7961   if (!priv->needs_width_request)
7962     {
7963       found_in_cache =
7964         _clutter_actor_get_cached_size_request (for_height,
7965                                                 priv->width_requests,
7966                                                 &cached_size_request);
7967     }
7968   else
7969     {
7970       /* if the actor needs a width request we use the first slot */
7971       found_in_cache = FALSE;
7972       cached_size_request = &priv->width_requests[0];
7973     }
7974
7975   if (!found_in_cache)
7976     {
7977       gfloat minimum_width, natural_width;
7978       ClutterActorClass *klass;
7979
7980       minimum_width = natural_width = 0;
7981
7982       /* adjust for the margin */
7983       if (for_height >= 0)
7984         {
7985           for_height -= (info->margin.top + info->margin.bottom);
7986           if (for_height < 0)
7987             for_height = 0;
7988         }
7989
7990       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7991
7992       klass = CLUTTER_ACTOR_GET_CLASS (self);
7993       klass->get_preferred_width (self, for_height,
7994                                   &minimum_width,
7995                                   &natural_width);
7996
7997       /* adjust for the margin */
7998       minimum_width += (info->margin.left + info->margin.right);
7999       natural_width += (info->margin.left + info->margin.right);
8000
8001       /* Due to accumulated float errors, it's better not to warn
8002        * on this, but just fix it.
8003        */
8004       if (natural_width < minimum_width)
8005         natural_width = minimum_width;
8006
8007       cached_size_request->min_size = minimum_width;
8008       cached_size_request->natural_size = natural_width;
8009       cached_size_request->for_size = for_height;
8010       cached_size_request->age = priv->cached_width_age;
8011
8012       priv->cached_width_age += 1;
8013       priv->needs_width_request = FALSE;
8014     }
8015
8016   if (!priv->min_width_set)
8017     request_min_width = cached_size_request->min_size;
8018   else
8019     request_min_width = info->min_width;
8020
8021   if (!priv->natural_width_set)
8022     request_natural_width = cached_size_request->natural_size;
8023   else
8024     request_natural_width = info->natural_width;
8025
8026   if (min_width_p)
8027     *min_width_p = request_min_width;
8028
8029   if (natural_width_p)
8030     *natural_width_p = request_natural_width;
8031 }
8032
8033 /**
8034  * clutter_actor_get_preferred_height:
8035  * @self: A #ClutterActor
8036  * @for_width: available width to assume in computing desired height,
8037  *   or a negative value to indicate that no width is defined
8038  * @min_height_p: (out) (allow-none): return location for minimum height,
8039  *   or %NULL
8040  * @natural_height_p: (out) (allow-none): return location for natural
8041  *   height, or %NULL
8042  *
8043  * Computes the requested minimum and natural heights for an actor,
8044  * or if they are already computed, returns the cached values.
8045  *
8046  * An actor may not get its request - depending on the layout
8047  * manager that's in effect.
8048  *
8049  * A request should not incorporate the actor's scale or anchor point;
8050  * those transformations do not affect layout, only rendering.
8051  *
8052  * Since: 0.8
8053  */
8054 void
8055 clutter_actor_get_preferred_height (ClutterActor *self,
8056                                     gfloat        for_width,
8057                                     gfloat       *min_height_p,
8058                                     gfloat       *natural_height_p)
8059 {
8060   float request_min_height, request_natural_height;
8061   SizeRequest *cached_size_request;
8062   const ClutterLayoutInfo *info;
8063   ClutterActorPrivate *priv;
8064   gboolean found_in_cache;
8065
8066   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8067
8068   priv = self->priv;
8069
8070   info = _clutter_actor_get_layout_info_or_defaults (self);
8071
8072   /* we shortcircuit the case of a fixed size set using set_height() */
8073   if (priv->min_height_set && priv->natural_height_set)
8074     {
8075       if (min_height_p != NULL)
8076         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
8077
8078       if (natural_height_p != NULL)
8079         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
8080
8081       return;
8082     }
8083
8084   /* the remaining cases are:
8085    *
8086    *   - either min_height or natural_height have been set
8087    *   - neither min_height or natural_height have been set
8088    *
8089    * in both cases, we go through the cache (and through the actor in case
8090    * of cache misses) and determine the authoritative value depending on
8091    * the *_set flags.
8092    */
8093
8094   if (!priv->needs_height_request)
8095     {
8096       found_in_cache =
8097         _clutter_actor_get_cached_size_request (for_width,
8098                                                 priv->height_requests,
8099                                                 &cached_size_request);
8100     }
8101   else
8102     {
8103       found_in_cache = FALSE;
8104       cached_size_request = &priv->height_requests[0];
8105     }
8106
8107   if (!found_in_cache)
8108     {
8109       gfloat minimum_height, natural_height;
8110       ClutterActorClass *klass;
8111
8112       minimum_height = natural_height = 0;
8113
8114       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8115
8116       /* adjust for margin */
8117       if (for_width >= 0)
8118         {
8119           for_width -= (info->margin.left + info->margin.right);
8120           if (for_width < 0)
8121             for_width = 0;
8122         }
8123
8124       klass = CLUTTER_ACTOR_GET_CLASS (self);
8125       klass->get_preferred_height (self, for_width,
8126                                    &minimum_height,
8127                                    &natural_height);
8128
8129       /* adjust for margin */
8130       minimum_height += (info->margin.top + info->margin.bottom);
8131       natural_height += (info->margin.top + info->margin.bottom);
8132
8133       /* Due to accumulated float errors, it's better not to warn
8134        * on this, but just fix it.
8135        */
8136       if (natural_height < minimum_height)
8137         natural_height = minimum_height;
8138
8139       cached_size_request->min_size = minimum_height;
8140       cached_size_request->natural_size = natural_height;
8141       cached_size_request->for_size = for_width;
8142       cached_size_request->age = priv->cached_height_age;
8143
8144       priv->cached_height_age += 1;
8145       priv->needs_height_request = FALSE;
8146     }
8147
8148   if (!priv->min_height_set)
8149     request_min_height = cached_size_request->min_size;
8150   else
8151     request_min_height = info->min_height;
8152
8153   if (!priv->natural_height_set)
8154     request_natural_height = cached_size_request->natural_size;
8155   else
8156     request_natural_height = info->natural_height;
8157
8158   if (min_height_p)
8159     *min_height_p = request_min_height;
8160
8161   if (natural_height_p)
8162     *natural_height_p = request_natural_height;
8163 }
8164
8165 /**
8166  * clutter_actor_get_allocation_box:
8167  * @self: A #ClutterActor
8168  * @box: (out): the function fills this in with the actor's allocation
8169  *
8170  * Gets the layout box an actor has been assigned. The allocation can
8171  * only be assumed valid inside a paint() method; anywhere else, it
8172  * may be out-of-date.
8173  *
8174  * An allocation does not incorporate the actor's scale or anchor point;
8175  * those transformations do not affect layout, only rendering.
8176  *
8177  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8178  * of functions inside the implementation of the get_preferred_width()
8179  * or get_preferred_height() virtual functions.</note>
8180  *
8181  * Since: 0.8
8182  */
8183 void
8184 clutter_actor_get_allocation_box (ClutterActor    *self,
8185                                   ClutterActorBox *box)
8186 {
8187   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8188
8189   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8190    * which limits calling get_allocation to inside paint() basically; or
8191    * we can 2) force a layout, which could be expensive if someone calls
8192    * get_allocation somewhere silly; or we can 3) just return the latest
8193    * value, allowing it to be out-of-date, and assume people know what
8194    * they are doing.
8195    *
8196    * The least-surprises approach that keeps existing code working is
8197    * likely to be 2). People can end up doing some inefficient things,
8198    * though, and in general code that requires 2) is probably broken.
8199    */
8200
8201   /* this implements 2) */
8202   if (G_UNLIKELY (self->priv->needs_allocation))
8203     {
8204       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8205
8206       /* do not queue a relayout on an unparented actor */
8207       if (stage)
8208         _clutter_stage_maybe_relayout (stage);
8209     }
8210
8211   /* commenting out the code above and just keeping this assigment
8212    * implements 3)
8213    */
8214   *box = self->priv->allocation;
8215 }
8216
8217 /**
8218  * clutter_actor_get_allocation_geometry:
8219  * @self: A #ClutterActor
8220  * @geom: (out): allocation geometry in pixels
8221  *
8222  * Gets the layout box an actor has been assigned.  The allocation can
8223  * only be assumed valid inside a paint() method; anywhere else, it
8224  * may be out-of-date.
8225  *
8226  * An allocation does not incorporate the actor's scale or anchor point;
8227  * those transformations do not affect layout, only rendering.
8228  *
8229  * The returned rectangle is in pixels.
8230  *
8231  * Since: 0.8
8232  */
8233 void
8234 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8235                                        ClutterGeometry *geom)
8236 {
8237   ClutterActorBox box;
8238
8239   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8240   g_return_if_fail (geom != NULL);
8241
8242   clutter_actor_get_allocation_box (self, &box);
8243
8244   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8245   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8246   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8247   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8248 }
8249
8250 static void
8251 clutter_actor_update_constraints (ClutterActor    *self,
8252                                   ClutterActorBox *allocation)
8253 {
8254   ClutterActorPrivate *priv = self->priv;
8255   const GList *constraints, *l;
8256
8257   if (priv->constraints == NULL)
8258     return;
8259
8260   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8261   for (l = constraints; l != NULL; l = l->next)
8262     {
8263       ClutterConstraint *constraint = l->data;
8264       ClutterActorMeta *meta = l->data;
8265
8266       if (clutter_actor_meta_get_enabled (meta))
8267         {
8268           _clutter_constraint_update_allocation (constraint,
8269                                                  self,
8270                                                  allocation);
8271
8272           CLUTTER_NOTE (LAYOUT,
8273                         "Allocation of '%s' after constraint '%s': "
8274                         "{ %.2f, %.2f, %.2f, %.2f }",
8275                         _clutter_actor_get_debug_name (self),
8276                         _clutter_actor_meta_get_debug_name (meta),
8277                         allocation->x1,
8278                         allocation->y1,
8279                         allocation->x2,
8280                         allocation->y2);
8281         }
8282     }
8283 }
8284
8285 /*< private >
8286  * clutter_actor_adjust_allocation:
8287  * @self: a #ClutterActor
8288  * @allocation: (inout): the allocation to adjust
8289  *
8290  * Adjusts the passed allocation box taking into account the actor's
8291  * layout information, like alignment, expansion, and margin.
8292  */
8293 static void
8294 clutter_actor_adjust_allocation (ClutterActor    *self,
8295                                  ClutterActorBox *allocation)
8296 {
8297   ClutterActorBox adj_allocation;
8298   float alloc_width, alloc_height;
8299   float min_width, min_height;
8300   float nat_width, nat_height;
8301   ClutterRequestMode req_mode;
8302
8303   adj_allocation = *allocation;
8304
8305   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8306
8307   /* we want to hit the cache, so we use the public API */
8308   req_mode = clutter_actor_get_request_mode (self);
8309
8310   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8311     {
8312       clutter_actor_get_preferred_width (self, -1,
8313                                          &min_width,
8314                                          &nat_width);
8315       clutter_actor_get_preferred_height (self, alloc_width,
8316                                           &min_height,
8317                                           &nat_height);
8318     }
8319   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8320     {
8321       clutter_actor_get_preferred_height (self, -1,
8322                                           &min_height,
8323                                           &nat_height);
8324       clutter_actor_get_preferred_height (self, alloc_height,
8325                                           &min_width,
8326                                           &nat_width);
8327     }
8328
8329 #ifdef CLUTTER_ENABLE_DEBUG
8330   /* warn about underallocations */
8331   if (_clutter_diagnostic_enabled () &&
8332       (floorf (min_width - alloc_width) > 0 ||
8333        floorf (min_height - alloc_height) > 0))
8334     {
8335       ClutterActor *parent = clutter_actor_get_parent (self);
8336
8337       /* the only actors that are allowed to be underallocated are the Stage,
8338        * as it doesn't have an implicit size, and Actors that specifically
8339        * told us that they want to opt-out from layout control mechanisms
8340        * through the NO_LAYOUT escape hatch.
8341        */
8342       if (parent != NULL &&
8343           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8344         {
8345           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8346                      "of %.2f x %.2f from its parent actor '%s', but its "
8347                      "requested minimum size is of %.2f x %.2f",
8348                      _clutter_actor_get_debug_name (self),
8349                      alloc_width, alloc_height,
8350                      _clutter_actor_get_debug_name (parent),
8351                      min_width, min_height);
8352         }
8353     }
8354 #endif
8355
8356   clutter_actor_adjust_width (self,
8357                               &min_width,
8358                               &nat_width,
8359                               &adj_allocation.x1,
8360                               &adj_allocation.x2);
8361
8362   clutter_actor_adjust_height (self,
8363                                &min_height,
8364                                &nat_height,
8365                                &adj_allocation.y1,
8366                                &adj_allocation.y2);
8367
8368   /* we maintain the invariant that an allocation cannot be adjusted
8369    * to be outside the parent-given box
8370    */
8371   if (adj_allocation.x1 < allocation->x1 ||
8372       adj_allocation.y1 < allocation->y1 ||
8373       adj_allocation.x2 > allocation->x2 ||
8374       adj_allocation.y2 > allocation->y2)
8375     {
8376       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8377                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8378                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8379                  _clutter_actor_get_debug_name (self),
8380                  adj_allocation.x1, adj_allocation.y1,
8381                  adj_allocation.x2 - adj_allocation.x1,
8382                  adj_allocation.y2 - adj_allocation.y1,
8383                  allocation->x1, allocation->y1,
8384                  allocation->x2 - allocation->x1,
8385                  allocation->y2 - allocation->y1);
8386       return;
8387     }
8388
8389   *allocation = adj_allocation;
8390 }
8391
8392 /**
8393  * clutter_actor_allocate:
8394  * @self: A #ClutterActor
8395  * @box: new allocation of the actor, in parent-relative coordinates
8396  * @flags: flags that control the allocation
8397  *
8398  * Called by the parent of an actor to assign the actor its size.
8399  * Should never be called by applications (except when implementing
8400  * a container or layout manager).
8401  *
8402  * Actors can know from their allocation box whether they have moved
8403  * with respect to their parent actor. The @flags parameter describes
8404  * additional information about the allocation, for instance whether
8405  * the parent has moved with respect to the stage, for example because
8406  * a grandparent's origin has moved.
8407  *
8408  * Since: 0.8
8409  */
8410 void
8411 clutter_actor_allocate (ClutterActor           *self,
8412                         const ClutterActorBox  *box,
8413                         ClutterAllocationFlags  flags)
8414 {
8415   ClutterActorPrivate *priv;
8416   ClutterActorClass *klass;
8417   ClutterActorBox old_allocation, real_allocation;
8418   gboolean origin_changed, child_moved, size_changed;
8419   gboolean stage_allocation_changed;
8420
8421   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8422   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8423     {
8424       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8425                  "which isn't a descendent of the stage!\n",
8426                  self, _clutter_actor_get_debug_name (self));
8427       return;
8428     }
8429
8430   priv = self->priv;
8431
8432   old_allocation = priv->allocation;
8433   real_allocation = *box;
8434
8435   /* constraints are allowed to modify the allocation only here; we do
8436    * this prior to all the other checks so that we can bail out if the
8437    * allocation did not change
8438    */
8439   clutter_actor_update_constraints (self, &real_allocation);
8440
8441   /* adjust the allocation depending on the align/margin properties */
8442   clutter_actor_adjust_allocation (self, &real_allocation);
8443
8444   if (real_allocation.x2 < real_allocation.x1 ||
8445       real_allocation.y2 < real_allocation.y1)
8446     {
8447       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8448                  _clutter_actor_get_debug_name (self),
8449                  real_allocation.x2 - real_allocation.x1,
8450                  real_allocation.y2 - real_allocation.y1);
8451     }
8452
8453   /* we allow 0-sized actors, but not negative-sized ones */
8454   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8455   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8456
8457   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8458
8459   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8460                  real_allocation.y1 != old_allocation.y1);
8461
8462   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8463                   real_allocation.y2 != old_allocation.y2);
8464
8465   if (origin_changed || child_moved || size_changed)
8466     stage_allocation_changed = TRUE;
8467   else
8468     stage_allocation_changed = FALSE;
8469
8470   /* If we get an allocation "out of the blue"
8471    * (we did not queue relayout), then we want to
8472    * ignore it. But if we have needs_allocation set,
8473    * we want to guarantee that allocate() virtual
8474    * method is always called, i.e. that queue_relayout()
8475    * always results in an allocate() invocation on
8476    * an actor.
8477    *
8478    * The optimization here is to avoid re-allocating
8479    * actors that did not queue relayout and were
8480    * not moved.
8481    */
8482   if (!priv->needs_allocation && !stage_allocation_changed)
8483     {
8484       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8485       return;
8486     }
8487
8488   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8489    * clutter_actor_allocate(), it indicates whether the parent has its
8490    * absolute origin moved; when passed in to ClutterActor::allocate()
8491    * virtual method though, it indicates whether the child has its
8492    * absolute origin moved.  So we set it when child_moved is TRUE
8493    */
8494   if (child_moved)
8495     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8496
8497   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8498
8499   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8500                 _clutter_actor_get_debug_name (self));
8501
8502   klass = CLUTTER_ACTOR_GET_CLASS (self);
8503   klass->allocate (self, &real_allocation, flags);
8504
8505   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8506
8507   if (stage_allocation_changed)
8508     clutter_actor_queue_redraw (self);
8509 }
8510
8511 /**
8512  * clutter_actor_set_allocation:
8513  * @self: a #ClutterActor
8514  * @box: a #ClutterActorBox
8515  * @flags: allocation flags
8516  *
8517  * Stores the allocation of @self as defined by @box.
8518  *
8519  * This function can only be called from within the implementation of
8520  * the #ClutterActorClass.allocate() virtual function.
8521  *
8522  * The allocation should have been adjusted to take into account constraints,
8523  * alignment, and margin properties. If you are implementing a #ClutterActor
8524  * subclass that provides its own layout management policy for its children
8525  * instead of using a #ClutterLayoutManager delegate, you should not call
8526  * this function on the children of @self; instead, you should call
8527  * clutter_actor_allocate(), which will adjust the allocation box for
8528  * you.
8529  *
8530  * This function should only be used by subclasses of #ClutterActor
8531  * that wish to store their allocation but cannot chain up to the
8532  * parent's implementation; the default implementation of the
8533  * #ClutterActorClass.allocate() virtual function will call this
8534  * function.
8535  *
8536  * It is important to note that, while chaining up was the recommended
8537  * behaviour for #ClutterActor subclasses prior to the introduction of
8538  * this function, it is recommended to call clutter_actor_set_allocation()
8539  * instead.
8540  *
8541  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8542  * to handle the allocation of its children, this function will call
8543  * the clutter_layout_manager_allocate() function only if the
8544  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8545  * expected that the subclass will call clutter_layout_manager_allocate()
8546  * by itself. For instance, the following code:
8547  *
8548  * |[
8549  * static void
8550  * my_actor_allocate (ClutterActor *actor,
8551  *                    const ClutterActorBox *allocation,
8552  *                    ClutterAllocationFlags flags)
8553  * {
8554  *   ClutterActorBox new_alloc;
8555  *   ClutterAllocationFlags new_flags;
8556  *
8557  *   adjust_allocation (allocation, &amp;new_alloc);
8558  *
8559  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8560  *
8561  *   /&ast; this will use the layout manager set on the actor &ast;/
8562  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8563  * }
8564  * ]|
8565  *
8566  * is equivalent to this:
8567  *
8568  * |[
8569  * static void
8570  * my_actor_allocate (ClutterActor *actor,
8571  *                    const ClutterActorBox *allocation,
8572  *                    ClutterAllocationFlags flags)
8573  * {
8574  *   ClutterLayoutManager *layout;
8575  *   ClutterActorBox new_alloc;
8576  *
8577  *   adjust_allocation (allocation, &amp;new_alloc);
8578  *
8579  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8580  *
8581  *   layout = clutter_actor_get_layout_manager (actor);
8582  *   clutter_layout_manager_allocate (layout,
8583  *                                    CLUTTER_CONTAINER (actor),
8584  *                                    &amp;new_alloc,
8585  *                                    flags);
8586  * }
8587  * ]|
8588  *
8589  * Since: 1.10
8590  */
8591 void
8592 clutter_actor_set_allocation (ClutterActor           *self,
8593                               const ClutterActorBox  *box,
8594                               ClutterAllocationFlags  flags)
8595 {
8596   ClutterActorPrivate *priv;
8597   gboolean changed;
8598
8599   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8600   g_return_if_fail (box != NULL);
8601
8602   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8603     {
8604       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8605                   "can only be called from within the implementation of "
8606                   "the ClutterActor::allocate() virtual function.");
8607       return;
8608     }
8609
8610   priv = self->priv;
8611
8612   g_object_freeze_notify (G_OBJECT (self));
8613
8614   changed = clutter_actor_set_allocation_internal (self, box, flags);
8615
8616   /* we allocate our children before we notify changes in our geometry,
8617    * so that people connecting to properties will be able to get valid
8618    * data out of the sub-tree of the scene graph that has this actor at
8619    * the root.
8620    */
8621   clutter_actor_maybe_layout_children (self, box, flags);
8622
8623   if (changed)
8624     {
8625       ClutterActorBox signal_box = priv->allocation;
8626       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8627
8628       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8629                      &signal_box,
8630                      signal_flags);
8631     }
8632
8633   g_object_thaw_notify (G_OBJECT (self));
8634 }
8635
8636 /**
8637  * clutter_actor_set_geometry:
8638  * @self: A #ClutterActor
8639  * @geometry: A #ClutterGeometry
8640  *
8641  * Sets the actor's fixed position and forces its minimum and natural
8642  * size, in pixels. This means the untransformed actor will have the
8643  * given geometry. This is the same as calling clutter_actor_set_position()
8644  * and clutter_actor_set_size().
8645  *
8646  * Deprecated: 1.10: Use clutter_actor_set_position() and
8647  *   clutter_actor_set_size() instead.
8648  */
8649 void
8650 clutter_actor_set_geometry (ClutterActor          *self,
8651                             const ClutterGeometry *geometry)
8652 {
8653   g_object_freeze_notify (G_OBJECT (self));
8654
8655   clutter_actor_set_position (self, geometry->x, geometry->y);
8656   clutter_actor_set_size (self, geometry->width, geometry->height);
8657
8658   g_object_thaw_notify (G_OBJECT (self));
8659 }
8660
8661 /**
8662  * clutter_actor_get_geometry:
8663  * @self: A #ClutterActor
8664  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8665  *
8666  * Gets the size and position of an actor relative to its parent
8667  * actor. This is the same as calling clutter_actor_get_position() and
8668  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8669  * requested size and position if the actor's allocation is invalid.
8670  *
8671  * Deprecated: 1.10: Use clutter_actor_get_position() and
8672  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8673  *   instead.
8674  */
8675 void
8676 clutter_actor_get_geometry (ClutterActor    *self,
8677                             ClutterGeometry *geometry)
8678 {
8679   gfloat x, y, width, height;
8680
8681   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8682   g_return_if_fail (geometry != NULL);
8683
8684   clutter_actor_get_position (self, &x, &y);
8685   clutter_actor_get_size (self, &width, &height);
8686
8687   geometry->x = (int) x;
8688   geometry->y = (int) y;
8689   geometry->width = (int) width;
8690   geometry->height = (int) height;
8691 }
8692
8693 /**
8694  * clutter_actor_set_position:
8695  * @self: A #ClutterActor
8696  * @x: New left position of actor in pixels.
8697  * @y: New top position of actor in pixels.
8698  *
8699  * Sets the actor's fixed position in pixels relative to any parent
8700  * actor.
8701  *
8702  * If a layout manager is in use, this position will override the
8703  * layout manager and force a fixed position.
8704  */
8705 void
8706 clutter_actor_set_position (ClutterActor *self,
8707                             gfloat        x,
8708                             gfloat        y)
8709 {
8710   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8711
8712   g_object_freeze_notify (G_OBJECT (self));
8713
8714   clutter_actor_set_x (self, x);
8715   clutter_actor_set_y (self, y);
8716
8717   g_object_thaw_notify (G_OBJECT (self));
8718 }
8719
8720 /**
8721  * clutter_actor_get_fixed_position_set:
8722  * @self: A #ClutterActor
8723  *
8724  * Checks whether an actor has a fixed position set (and will thus be
8725  * unaffected by any layout manager).
8726  *
8727  * Return value: %TRUE if the fixed position is set on the actor
8728  *
8729  * Since: 0.8
8730  */
8731 gboolean
8732 clutter_actor_get_fixed_position_set (ClutterActor *self)
8733 {
8734   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8735
8736   return self->priv->position_set;
8737 }
8738
8739 /**
8740  * clutter_actor_set_fixed_position_set:
8741  * @self: A #ClutterActor
8742  * @is_set: whether to use fixed position
8743  *
8744  * Sets whether an actor has a fixed position set (and will thus be
8745  * unaffected by any layout manager).
8746  *
8747  * Since: 0.8
8748  */
8749 void
8750 clutter_actor_set_fixed_position_set (ClutterActor *self,
8751                                       gboolean      is_set)
8752 {
8753   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8754
8755   if (self->priv->position_set == (is_set != FALSE))
8756     return;
8757
8758   self->priv->position_set = is_set != FALSE;
8759   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8760
8761   clutter_actor_queue_relayout (self);
8762 }
8763
8764 /**
8765  * clutter_actor_move_by:
8766  * @self: A #ClutterActor
8767  * @dx: Distance to move Actor on X axis.
8768  * @dy: Distance to move Actor on Y axis.
8769  *
8770  * Moves an actor by the specified distance relative to its current
8771  * position in pixels.
8772  *
8773  * This function modifies the fixed position of an actor and thus removes
8774  * it from any layout management. Another way to move an actor is with an
8775  * anchor point, see clutter_actor_set_anchor_point().
8776  *
8777  * Since: 0.2
8778  */
8779 void
8780 clutter_actor_move_by (ClutterActor *self,
8781                        gfloat        dx,
8782                        gfloat        dy)
8783 {
8784   const ClutterLayoutInfo *info;
8785   gfloat x, y;
8786
8787   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8788
8789   info = _clutter_actor_get_layout_info_or_defaults (self);
8790   x = info->fixed_x;
8791   y = info->fixed_y;
8792
8793   clutter_actor_set_position (self, x + dx, y + dy);
8794 }
8795
8796 static void
8797 clutter_actor_set_min_width (ClutterActor *self,
8798                              gfloat        min_width)
8799 {
8800   ClutterActorPrivate *priv = self->priv;
8801   ClutterActorBox old = { 0, };
8802   ClutterLayoutInfo *info;
8803
8804   /* if we are setting the size on a top-level actor and the
8805    * backend only supports static top-levels (e.g. framebuffers)
8806    * then we ignore the passed value and we override it with
8807    * the stage implementation's preferred size.
8808    */
8809   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8810       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8811     return;
8812
8813   info = _clutter_actor_get_layout_info (self);
8814
8815   if (priv->min_width_set && min_width == info->min_width)
8816     return;
8817
8818   g_object_freeze_notify (G_OBJECT (self));
8819
8820   clutter_actor_store_old_geometry (self, &old);
8821
8822   info->min_width = min_width;
8823   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8824   clutter_actor_set_min_width_set (self, TRUE);
8825
8826   clutter_actor_notify_if_geometry_changed (self, &old);
8827
8828   g_object_thaw_notify (G_OBJECT (self));
8829
8830   clutter_actor_queue_relayout (self);
8831 }
8832
8833 static void
8834 clutter_actor_set_min_height (ClutterActor *self,
8835                               gfloat        min_height)
8836
8837 {
8838   ClutterActorPrivate *priv = self->priv;
8839   ClutterActorBox old = { 0, };
8840   ClutterLayoutInfo *info;
8841
8842   /* if we are setting the size on a top-level actor and the
8843    * backend only supports static top-levels (e.g. framebuffers)
8844    * then we ignore the passed value and we override it with
8845    * the stage implementation's preferred size.
8846    */
8847   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8848       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8849     return;
8850
8851   info = _clutter_actor_get_layout_info (self);
8852
8853   if (priv->min_height_set && min_height == info->min_height)
8854     return;
8855
8856   g_object_freeze_notify (G_OBJECT (self));
8857
8858   clutter_actor_store_old_geometry (self, &old);
8859
8860   info->min_height = min_height;
8861   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8862   clutter_actor_set_min_height_set (self, TRUE);
8863
8864   clutter_actor_notify_if_geometry_changed (self, &old);
8865
8866   g_object_thaw_notify (G_OBJECT (self));
8867
8868   clutter_actor_queue_relayout (self);
8869 }
8870
8871 static void
8872 clutter_actor_set_natural_width (ClutterActor *self,
8873                                  gfloat        natural_width)
8874 {
8875   ClutterActorPrivate *priv = self->priv;
8876   ClutterActorBox old = { 0, };
8877   ClutterLayoutInfo *info;
8878
8879   /* if we are setting the size on a top-level actor and the
8880    * backend only supports static top-levels (e.g. framebuffers)
8881    * then we ignore the passed value and we override it with
8882    * the stage implementation's preferred size.
8883    */
8884   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8885       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8886     return;
8887
8888   info = _clutter_actor_get_layout_info (self);
8889
8890   if (priv->natural_width_set && natural_width == info->natural_width)
8891     return;
8892
8893   g_object_freeze_notify (G_OBJECT (self));
8894
8895   clutter_actor_store_old_geometry (self, &old);
8896
8897   info->natural_width = natural_width;
8898   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8899   clutter_actor_set_natural_width_set (self, TRUE);
8900
8901   clutter_actor_notify_if_geometry_changed (self, &old);
8902
8903   g_object_thaw_notify (G_OBJECT (self));
8904
8905   clutter_actor_queue_relayout (self);
8906 }
8907
8908 static void
8909 clutter_actor_set_natural_height (ClutterActor *self,
8910                                   gfloat        natural_height)
8911 {
8912   ClutterActorPrivate *priv = self->priv;
8913   ClutterActorBox old = { 0, };
8914   ClutterLayoutInfo *info;
8915
8916   /* if we are setting the size on a top-level actor and the
8917    * backend only supports static top-levels (e.g. framebuffers)
8918    * then we ignore the passed value and we override it with
8919    * the stage implementation's preferred size.
8920    */
8921   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8922       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8923     return;
8924
8925   info = _clutter_actor_get_layout_info (self);
8926
8927   if (priv->natural_height_set && natural_height == info->natural_height)
8928     return;
8929
8930   g_object_freeze_notify (G_OBJECT (self));
8931
8932   clutter_actor_store_old_geometry (self, &old);
8933
8934   info->natural_height = natural_height;
8935   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8936   clutter_actor_set_natural_height_set (self, TRUE);
8937
8938   clutter_actor_notify_if_geometry_changed (self, &old);
8939
8940   g_object_thaw_notify (G_OBJECT (self));
8941
8942   clutter_actor_queue_relayout (self);
8943 }
8944
8945 static void
8946 clutter_actor_set_min_width_set (ClutterActor *self,
8947                                  gboolean      use_min_width)
8948 {
8949   ClutterActorPrivate *priv = self->priv;
8950   ClutterActorBox old = { 0, };
8951
8952   if (priv->min_width_set == (use_min_width != FALSE))
8953     return;
8954
8955   clutter_actor_store_old_geometry (self, &old);
8956
8957   priv->min_width_set = use_min_width != FALSE;
8958   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8959
8960   clutter_actor_notify_if_geometry_changed (self, &old);
8961
8962   clutter_actor_queue_relayout (self);
8963 }
8964
8965 static void
8966 clutter_actor_set_min_height_set (ClutterActor *self,
8967                                   gboolean      use_min_height)
8968 {
8969   ClutterActorPrivate *priv = self->priv;
8970   ClutterActorBox old = { 0, };
8971
8972   if (priv->min_height_set == (use_min_height != FALSE))
8973     return;
8974
8975   clutter_actor_store_old_geometry (self, &old);
8976
8977   priv->min_height_set = use_min_height != FALSE;
8978   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8979
8980   clutter_actor_notify_if_geometry_changed (self, &old);
8981
8982   clutter_actor_queue_relayout (self);
8983 }
8984
8985 static void
8986 clutter_actor_set_natural_width_set (ClutterActor *self,
8987                                      gboolean      use_natural_width)
8988 {
8989   ClutterActorPrivate *priv = self->priv;
8990   ClutterActorBox old = { 0, };
8991
8992   if (priv->natural_width_set == (use_natural_width != FALSE))
8993     return;
8994
8995   clutter_actor_store_old_geometry (self, &old);
8996
8997   priv->natural_width_set = use_natural_width != FALSE;
8998   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
8999
9000   clutter_actor_notify_if_geometry_changed (self, &old);
9001
9002   clutter_actor_queue_relayout (self);
9003 }
9004
9005 static void
9006 clutter_actor_set_natural_height_set (ClutterActor *self,
9007                                       gboolean      use_natural_height)
9008 {
9009   ClutterActorPrivate *priv = self->priv;
9010   ClutterActorBox old = { 0, };
9011
9012   if (priv->natural_height_set == (use_natural_height != FALSE))
9013     return;
9014
9015   clutter_actor_store_old_geometry (self, &old);
9016
9017   priv->natural_height_set = use_natural_height != FALSE;
9018   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9019
9020   clutter_actor_notify_if_geometry_changed (self, &old);
9021
9022   clutter_actor_queue_relayout (self);
9023 }
9024
9025 /**
9026  * clutter_actor_set_request_mode:
9027  * @self: a #ClutterActor
9028  * @mode: the request mode
9029  *
9030  * Sets the geometry request mode of @self.
9031  *
9032  * The @mode determines the order for invoking
9033  * clutter_actor_get_preferred_width() and
9034  * clutter_actor_get_preferred_height()
9035  *
9036  * Since: 1.2
9037  */
9038 void
9039 clutter_actor_set_request_mode (ClutterActor       *self,
9040                                 ClutterRequestMode  mode)
9041 {
9042   ClutterActorPrivate *priv;
9043
9044   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9045
9046   priv = self->priv;
9047
9048   if (priv->request_mode == mode)
9049     return;
9050
9051   priv->request_mode = mode;
9052
9053   priv->needs_width_request = TRUE;
9054   priv->needs_height_request = TRUE;
9055
9056   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9057
9058   clutter_actor_queue_relayout (self);
9059 }
9060
9061 /**
9062  * clutter_actor_get_request_mode:
9063  * @self: a #ClutterActor
9064  *
9065  * Retrieves the geometry request mode of @self
9066  *
9067  * Return value: the request mode for the actor
9068  *
9069  * Since: 1.2
9070  */
9071 ClutterRequestMode
9072 clutter_actor_get_request_mode (ClutterActor *self)
9073 {
9074   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9075                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9076
9077   return self->priv->request_mode;
9078 }
9079
9080 /* variant of set_width() without checks and without notification
9081  * freeze+thaw, for internal usage only
9082  */
9083 static inline void
9084 clutter_actor_set_width_internal (ClutterActor *self,
9085                                   gfloat        width)
9086 {
9087   if (width >= 0)
9088     {
9089       /* the Stage will use the :min-width to control the minimum
9090        * width to be resized to, so we should not be setting it
9091        * along with the :natural-width
9092        */
9093       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9094         clutter_actor_set_min_width (self, width);
9095
9096       clutter_actor_set_natural_width (self, width);
9097     }
9098   else
9099     {
9100       /* we only unset the :natural-width for the Stage */
9101       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9102         clutter_actor_set_min_width_set (self, FALSE);
9103
9104       clutter_actor_set_natural_width_set (self, FALSE);
9105     }
9106 }
9107
9108 /* variant of set_height() without checks and without notification
9109  * freeze+thaw, for internal usage only
9110  */
9111 static inline void
9112 clutter_actor_set_height_internal (ClutterActor *self,
9113                                    gfloat        height)
9114 {
9115   if (height >= 0)
9116     {
9117       /* see the comment above in set_width_internal() */
9118       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9119         clutter_actor_set_min_height (self, height);
9120
9121       clutter_actor_set_natural_height (self, height);
9122     }
9123   else
9124     {
9125       /* see the comment above in set_width_internal() */
9126       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9127         clutter_actor_set_min_height_set (self, FALSE);
9128
9129       clutter_actor_set_natural_height_set (self, FALSE);
9130     }
9131 }
9132
9133 /**
9134  * clutter_actor_set_size:
9135  * @self: A #ClutterActor
9136  * @width: New width of actor in pixels, or -1
9137  * @height: New height of actor in pixels, or -1
9138  *
9139  * Sets the actor's size request in pixels. This overrides any
9140  * "normal" size request the actor would have. For example
9141  * a text actor might normally request the size of the text;
9142  * this function would force a specific size instead.
9143  *
9144  * If @width and/or @height are -1 the actor will use its
9145  * "normal" size request instead of overriding it, i.e.
9146  * you can "unset" the size with -1.
9147  *
9148  * This function sets or unsets both the minimum and natural size.
9149  */
9150 void
9151 clutter_actor_set_size (ClutterActor *self,
9152                         gfloat        width,
9153                         gfloat        height)
9154 {
9155   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9156
9157   g_object_freeze_notify (G_OBJECT (self));
9158
9159   clutter_actor_set_width (self, width);
9160   clutter_actor_set_height (self, height);
9161
9162   g_object_thaw_notify (G_OBJECT (self));
9163 }
9164
9165 /**
9166  * clutter_actor_get_size:
9167  * @self: A #ClutterActor
9168  * @width: (out) (allow-none): return location for the width, or %NULL.
9169  * @height: (out) (allow-none): return location for the height, or %NULL.
9170  *
9171  * This function tries to "do what you mean" and return
9172  * the size an actor will have. If the actor has a valid
9173  * allocation, the allocation will be returned; otherwise,
9174  * the actors natural size request will be returned.
9175  *
9176  * If you care whether you get the request vs. the allocation, you
9177  * should probably call a different function like
9178  * clutter_actor_get_allocation_box() or
9179  * clutter_actor_get_preferred_width().
9180  *
9181  * Since: 0.2
9182  */
9183 void
9184 clutter_actor_get_size (ClutterActor *self,
9185                         gfloat       *width,
9186                         gfloat       *height)
9187 {
9188   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9189
9190   if (width)
9191     *width = clutter_actor_get_width (self);
9192
9193   if (height)
9194     *height = clutter_actor_get_height (self);
9195 }
9196
9197 /**
9198  * clutter_actor_get_position:
9199  * @self: a #ClutterActor
9200  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9201  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9202  *
9203  * This function tries to "do what you mean" and tell you where the
9204  * actor is, prior to any transformations. Retrieves the fixed
9205  * position of an actor in pixels, if one has been set; otherwise, if
9206  * the allocation is valid, returns the actor's allocated position;
9207  * otherwise, returns 0,0.
9208  *
9209  * The returned position is in pixels.
9210  *
9211  * Since: 0.6
9212  */
9213 void
9214 clutter_actor_get_position (ClutterActor *self,
9215                             gfloat       *x,
9216                             gfloat       *y)
9217 {
9218   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9219
9220   if (x)
9221     *x = clutter_actor_get_x (self);
9222
9223   if (y)
9224     *y = clutter_actor_get_y (self);
9225 }
9226
9227 /**
9228  * clutter_actor_get_transformed_position:
9229  * @self: A #ClutterActor
9230  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9231  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9232  *
9233  * Gets the absolute position of an actor, in pixels relative to the stage.
9234  *
9235  * Since: 0.8
9236  */
9237 void
9238 clutter_actor_get_transformed_position (ClutterActor *self,
9239                                         gfloat       *x,
9240                                         gfloat       *y)
9241 {
9242   ClutterVertex v1;
9243   ClutterVertex v2;
9244
9245   v1.x = v1.y = v1.z = 0;
9246   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9247
9248   if (x)
9249     *x = v2.x;
9250
9251   if (y)
9252     *y = v2.y;
9253 }
9254
9255 /**
9256  * clutter_actor_get_transformed_size:
9257  * @self: A #ClutterActor
9258  * @width: (out) (allow-none): return location for the width, or %NULL
9259  * @height: (out) (allow-none): return location for the height, or %NULL
9260  *
9261  * Gets the absolute size of an actor in pixels, taking into account the
9262  * scaling factors.
9263  *
9264  * If the actor has a valid allocation, the allocated size will be used.
9265  * If the actor has not a valid allocation then the preferred size will
9266  * be transformed and returned.
9267  *
9268  * If you want the transformed allocation, see
9269  * clutter_actor_get_abs_allocation_vertices() instead.
9270  *
9271  * <note>When the actor (or one of its ancestors) is rotated around the
9272  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9273  * as a generic quadrangle; in that case this function returns the size
9274  * of the smallest rectangle that encapsulates the entire quad. Please
9275  * note that in this case no assumptions can be made about the relative
9276  * position of this envelope to the absolute position of the actor, as
9277  * returned by clutter_actor_get_transformed_position(); if you need this
9278  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9279  * to get the coords of the actual quadrangle.</note>
9280  *
9281  * Since: 0.8
9282  */
9283 void
9284 clutter_actor_get_transformed_size (ClutterActor *self,
9285                                     gfloat       *width,
9286                                     gfloat       *height)
9287 {
9288   ClutterActorPrivate *priv;
9289   ClutterVertex v[4];
9290   gfloat x_min, x_max, y_min, y_max;
9291   gint i;
9292
9293   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9294
9295   priv = self->priv;
9296
9297   /* if the actor hasn't been allocated yet, get the preferred
9298    * size and transform that
9299    */
9300   if (priv->needs_allocation)
9301     {
9302       gfloat natural_width, natural_height;
9303       ClutterActorBox box;
9304
9305       /* Make a fake allocation to transform.
9306        *
9307        * NB: _clutter_actor_transform_and_project_box expects a box in
9308        * the actor's coordinate space... */
9309
9310       box.x1 = 0;
9311       box.y1 = 0;
9312
9313       natural_width = natural_height = 0;
9314       clutter_actor_get_preferred_size (self, NULL, NULL,
9315                                         &natural_width,
9316                                         &natural_height);
9317
9318       box.x2 = natural_width;
9319       box.y2 = natural_height;
9320
9321       _clutter_actor_transform_and_project_box (self, &box, v);
9322     }
9323   else
9324     clutter_actor_get_abs_allocation_vertices (self, v);
9325
9326   x_min = x_max = v[0].x;
9327   y_min = y_max = v[0].y;
9328
9329   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9330     {
9331       if (v[i].x < x_min)
9332         x_min = v[i].x;
9333
9334       if (v[i].x > x_max)
9335         x_max = v[i].x;
9336
9337       if (v[i].y < y_min)
9338         y_min = v[i].y;
9339
9340       if (v[i].y > y_max)
9341         y_max = v[i].y;
9342     }
9343
9344   if (width)
9345     *width  = x_max - x_min;
9346
9347   if (height)
9348     *height = y_max - y_min;
9349 }
9350
9351 /**
9352  * clutter_actor_get_width:
9353  * @self: A #ClutterActor
9354  *
9355  * Retrieves the width of a #ClutterActor.
9356  *
9357  * If the actor has a valid allocation, this function will return the
9358  * width of the allocated area given to the actor.
9359  *
9360  * If the actor does not have a valid allocation, this function will
9361  * return the actor's natural width, that is the preferred width of
9362  * the actor.
9363  *
9364  * If you care whether you get the preferred width or the width that
9365  * has been assigned to the actor, you should probably call a different
9366  * function like clutter_actor_get_allocation_box() to retrieve the
9367  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9368  * preferred width.
9369  *
9370  * If an actor has a fixed width, for instance a width that has been
9371  * assigned using clutter_actor_set_width(), the width returned will
9372  * be the same value.
9373  *
9374  * Return value: the width of the actor, in pixels
9375  */
9376 gfloat
9377 clutter_actor_get_width (ClutterActor *self)
9378 {
9379   ClutterActorPrivate *priv;
9380
9381   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9382
9383   priv = self->priv;
9384
9385   if (priv->needs_allocation)
9386     {
9387       gfloat natural_width = 0;
9388
9389       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9390         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9391       else
9392         {
9393           gfloat natural_height = 0;
9394
9395           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9396           clutter_actor_get_preferred_width (self, natural_height,
9397                                              NULL,
9398                                              &natural_width);
9399         }
9400
9401       return natural_width;
9402     }
9403   else
9404     return priv->allocation.x2 - priv->allocation.x1;
9405 }
9406
9407 /**
9408  * clutter_actor_get_height:
9409  * @self: A #ClutterActor
9410  *
9411  * Retrieves the height of a #ClutterActor.
9412  *
9413  * If the actor has a valid allocation, this function will return the
9414  * height of the allocated area given to the actor.
9415  *
9416  * If the actor does not have a valid allocation, this function will
9417  * return the actor's natural height, that is the preferred height of
9418  * the actor.
9419  *
9420  * If you care whether you get the preferred height or the height that
9421  * has been assigned to the actor, you should probably call a different
9422  * function like clutter_actor_get_allocation_box() to retrieve the
9423  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9424  * preferred height.
9425  *
9426  * If an actor has a fixed height, for instance a height that has been
9427  * assigned using clutter_actor_set_height(), the height returned will
9428  * be the same value.
9429  *
9430  * Return value: the height of the actor, in pixels
9431  */
9432 gfloat
9433 clutter_actor_get_height (ClutterActor *self)
9434 {
9435   ClutterActorPrivate *priv;
9436
9437   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9438
9439   priv = self->priv;
9440
9441   if (priv->needs_allocation)
9442     {
9443       gfloat natural_height = 0;
9444
9445       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9446         {
9447           gfloat natural_width = 0;
9448
9449           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9450           clutter_actor_get_preferred_height (self, natural_width,
9451                                               NULL, &natural_height);
9452         }
9453       else
9454         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9455
9456       return natural_height;
9457     }
9458   else
9459     return priv->allocation.y2 - priv->allocation.y1;
9460 }
9461
9462 /**
9463  * clutter_actor_set_width:
9464  * @self: A #ClutterActor
9465  * @width: Requested new width for the actor, in pixels, or -1
9466  *
9467  * Forces a width on an actor, causing the actor's preferred width
9468  * and height (if any) to be ignored.
9469  *
9470  * If @width is -1 the actor will use its preferred width request
9471  * instead of overriding it, i.e. you can "unset" the width with -1.
9472  *
9473  * This function sets both the minimum and natural size of the actor.
9474  *
9475  * since: 0.2
9476  */
9477 void
9478 clutter_actor_set_width (ClutterActor *self,
9479                          gfloat        width)
9480 {
9481   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9482
9483   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9484     {
9485       float cur_size;
9486
9487       /* minor optimization: if we don't have a duration
9488        * then we can skip the get_width() below, to avoid
9489        * the chance of going through get_preferred_width()
9490        * just to jump to a new desired width.
9491        */
9492       if (clutter_actor_get_easing_duration (self) == 0)
9493         {
9494           g_object_freeze_notify (G_OBJECT (self));
9495
9496           clutter_actor_set_width_internal (self, width);
9497
9498           g_object_thaw_notify (G_OBJECT (self));
9499
9500           return;
9501         }
9502       else
9503         cur_size = clutter_actor_get_width (self);
9504
9505       _clutter_actor_create_transition (self,
9506                                         obj_props[PROP_WIDTH],
9507                                         cur_size,
9508                                         width);
9509     }
9510   else
9511     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9512
9513   clutter_actor_queue_relayout (self);
9514 }
9515
9516 /**
9517  * clutter_actor_set_height:
9518  * @self: A #ClutterActor
9519  * @height: Requested new height for the actor, in pixels, or -1
9520  *
9521  * Forces a height on an actor, causing the actor's preferred width
9522  * and height (if any) to be ignored.
9523  *
9524  * If @height is -1 the actor will use its preferred height instead of
9525  * overriding it, i.e. you can "unset" the height with -1.
9526  *
9527  * This function sets both the minimum and natural size of the actor.
9528  *
9529  * since: 0.2
9530  */
9531 void
9532 clutter_actor_set_height (ClutterActor *self,
9533                           gfloat        height)
9534 {
9535   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9536
9537   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9538     {
9539       float cur_size;
9540
9541       /* see the comment in clutter_actor_set_width() above */
9542       if (clutter_actor_get_easing_duration (self) == 0)
9543         {
9544           g_object_freeze_notify (G_OBJECT (self));
9545
9546           clutter_actor_set_height_internal (self, height);
9547
9548           g_object_thaw_notify (G_OBJECT (self));
9549
9550           return;
9551         }
9552       else
9553         cur_size = clutter_actor_get_height (self);
9554
9555       _clutter_actor_create_transition (self,
9556                                         obj_props[PROP_HEIGHT],
9557                                         cur_size,
9558                                         height);
9559     }
9560   else
9561     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9562
9563   clutter_actor_queue_relayout (self);
9564 }
9565
9566 static inline void
9567 clutter_actor_set_x_internal (ClutterActor *self,
9568                               float         x)
9569 {
9570   ClutterActorPrivate *priv = self->priv;
9571   ClutterLayoutInfo *linfo;
9572   ClutterActorBox old = { 0, };
9573
9574   linfo = _clutter_actor_get_layout_info (self);
9575
9576   if (priv->position_set && linfo->fixed_x == x)
9577     return;
9578
9579   clutter_actor_store_old_geometry (self, &old);
9580
9581   linfo->fixed_x = x;
9582   clutter_actor_set_fixed_position_set (self, TRUE);
9583
9584   clutter_actor_notify_if_geometry_changed (self, &old);
9585
9586   clutter_actor_queue_relayout (self);
9587 }
9588
9589 static inline void
9590 clutter_actor_set_y_internal (ClutterActor *self,
9591                               float         y)
9592 {
9593   ClutterActorPrivate *priv = self->priv;
9594   ClutterLayoutInfo *linfo;
9595   ClutterActorBox old = { 0, };
9596
9597   linfo = _clutter_actor_get_layout_info (self);
9598
9599   if (priv->position_set && linfo->fixed_y == y)
9600     return;
9601
9602   clutter_actor_store_old_geometry (self, &old);
9603
9604   linfo->fixed_y = y;
9605   clutter_actor_set_fixed_position_set (self, TRUE);
9606
9607   clutter_actor_notify_if_geometry_changed (self, &old);
9608
9609   clutter_actor_queue_relayout (self);
9610 }
9611
9612 /**
9613  * clutter_actor_set_x:
9614  * @self: a #ClutterActor
9615  * @x: the actor's position on the X axis
9616  *
9617  * Sets the actor's X coordinate, relative to its parent, in pixels.
9618  *
9619  * Overrides any layout manager and forces a fixed position for
9620  * the actor.
9621  *
9622  * The #ClutterActor:x property is animatable.
9623  *
9624  * Since: 0.6
9625  */
9626 void
9627 clutter_actor_set_x (ClutterActor *self,
9628                      gfloat        x)
9629 {
9630   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9631
9632   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9633     {
9634       float cur_position = clutter_actor_get_x (self);
9635
9636       _clutter_actor_create_transition (self, obj_props[PROP_X],
9637                                         cur_position,
9638                                         x);
9639     }
9640   else
9641     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9642
9643   clutter_actor_queue_relayout (self);
9644 }
9645
9646 /**
9647  * clutter_actor_set_y:
9648  * @self: a #ClutterActor
9649  * @y: the actor's position on the Y axis
9650  *
9651  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9652  *
9653  * Overrides any layout manager and forces a fixed position for
9654  * the actor.
9655  *
9656  * The #ClutterActor:y property is animatable.
9657  *
9658  * Since: 0.6
9659  */
9660 void
9661 clutter_actor_set_y (ClutterActor *self,
9662                      gfloat        y)
9663 {
9664   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9665
9666   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9667     {
9668       float cur_position = clutter_actor_get_y (self);
9669
9670       _clutter_actor_create_transition (self, obj_props[PROP_Y],
9671                                         cur_position,
9672                                         y);
9673     }
9674   else
9675     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9676
9677   clutter_actor_queue_relayout (self);
9678 }
9679
9680 /**
9681  * clutter_actor_get_x:
9682  * @self: A #ClutterActor
9683  *
9684  * Retrieves the X coordinate of a #ClutterActor.
9685  *
9686  * This function tries to "do what you mean", by returning the
9687  * correct value depending on the actor's state.
9688  *
9689  * If the actor has a valid allocation, this function will return
9690  * the X coordinate of the origin of the allocation box.
9691  *
9692  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9693  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9694  * function will return that coordinate.
9695  *
9696  * If both the allocation and a fixed position are missing, this function
9697  * will return 0.
9698  *
9699  * Return value: the X coordinate, in pixels, ignoring any
9700  *   transformation (i.e. scaling, rotation)
9701  */
9702 gfloat
9703 clutter_actor_get_x (ClutterActor *self)
9704 {
9705   ClutterActorPrivate *priv;
9706
9707   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9708
9709   priv = self->priv;
9710
9711   if (priv->needs_allocation)
9712     {
9713       if (priv->position_set)
9714         {
9715           const ClutterLayoutInfo *info;
9716
9717           info = _clutter_actor_get_layout_info_or_defaults (self);
9718
9719           return info->fixed_x;
9720         }
9721       else
9722         return 0;
9723     }
9724   else
9725     return priv->allocation.x1;
9726 }
9727
9728 /**
9729  * clutter_actor_get_y:
9730  * @self: A #ClutterActor
9731  *
9732  * Retrieves the Y coordinate of a #ClutterActor.
9733  *
9734  * This function tries to "do what you mean", by returning the
9735  * correct value depending on the actor's state.
9736  *
9737  * If the actor has a valid allocation, this function will return
9738  * the Y coordinate of the origin of the allocation box.
9739  *
9740  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9741  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9742  * function will return that coordinate.
9743  *
9744  * If both the allocation and a fixed position are missing, this function
9745  * will return 0.
9746  *
9747  * Return value: the Y coordinate, in pixels, ignoring any
9748  *   transformation (i.e. scaling, rotation)
9749  */
9750 gfloat
9751 clutter_actor_get_y (ClutterActor *self)
9752 {
9753   ClutterActorPrivate *priv;
9754
9755   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9756
9757   priv = self->priv;
9758
9759   if (priv->needs_allocation)
9760     {
9761       if (priv->position_set)
9762         {
9763           const ClutterLayoutInfo *info;
9764
9765           info = _clutter_actor_get_layout_info_or_defaults (self);
9766
9767           return info->fixed_y;
9768         }
9769       else
9770         return 0;
9771     }
9772   else
9773     return priv->allocation.y1;
9774 }
9775
9776 /**
9777  * clutter_actor_set_scale:
9778  * @self: A #ClutterActor
9779  * @scale_x: double factor to scale actor by horizontally.
9780  * @scale_y: double factor to scale actor by vertically.
9781  *
9782  * Scales an actor with the given factors. The scaling is relative to
9783  * the scale center and the anchor point. The scale center is
9784  * unchanged by this function and defaults to 0,0.
9785  *
9786  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9787  * animatable.
9788  *
9789  * Since: 0.2
9790  */
9791 void
9792 clutter_actor_set_scale (ClutterActor *self,
9793                          gdouble       scale_x,
9794                          gdouble       scale_y)
9795 {
9796   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9797
9798   g_object_freeze_notify (G_OBJECT (self));
9799
9800   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9801   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9802
9803   g_object_thaw_notify (G_OBJECT (self));
9804 }
9805
9806 /**
9807  * clutter_actor_set_scale_full:
9808  * @self: A #ClutterActor
9809  * @scale_x: double factor to scale actor by horizontally.
9810  * @scale_y: double factor to scale actor by vertically.
9811  * @center_x: X coordinate of the center of the scale.
9812  * @center_y: Y coordinate of the center of the scale
9813  *
9814  * Scales an actor with the given factors around the given center
9815  * point. The center point is specified in pixels relative to the
9816  * anchor point (usually the top left corner of the actor).
9817  *
9818  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9819  * are animatable.
9820  *
9821  * Since: 1.0
9822  */
9823 void
9824 clutter_actor_set_scale_full (ClutterActor *self,
9825                               gdouble       scale_x,
9826                               gdouble       scale_y,
9827                               gfloat        center_x,
9828                               gfloat        center_y)
9829 {
9830   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9831
9832   g_object_freeze_notify (G_OBJECT (self));
9833
9834   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9835   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9836   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9837   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9838
9839   g_object_thaw_notify (G_OBJECT (self));
9840 }
9841
9842 /**
9843  * clutter_actor_set_scale_with_gravity:
9844  * @self: A #ClutterActor
9845  * @scale_x: double factor to scale actor by horizontally.
9846  * @scale_y: double factor to scale actor by vertically.
9847  * @gravity: the location of the scale center expressed as a compass
9848  * direction.
9849  *
9850  * Scales an actor with the given factors around the given
9851  * center point. The center point is specified as one of the compass
9852  * directions in #ClutterGravity. For example, setting it to north
9853  * will cause the top of the actor to remain unchanged and the rest of
9854  * the actor to expand left, right and downwards.
9855  *
9856  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9857  * animatable.
9858  *
9859  * Since: 1.0
9860  */
9861 void
9862 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9863                                       gdouble         scale_x,
9864                                       gdouble         scale_y,
9865                                       ClutterGravity  gravity)
9866 {
9867   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9868
9869   g_object_freeze_notify (G_OBJECT (self));
9870
9871   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9872   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9873   clutter_actor_set_scale_gravity (self, gravity);
9874
9875   g_object_thaw_notify (G_OBJECT (self));
9876 }
9877
9878 /**
9879  * clutter_actor_get_scale:
9880  * @self: A #ClutterActor
9881  * @scale_x: (out) (allow-none): Location to store horizonal
9882  *   scale factor, or %NULL.
9883  * @scale_y: (out) (allow-none): Location to store vertical
9884  *   scale factor, or %NULL.
9885  *
9886  * Retrieves an actors scale factors.
9887  *
9888  * Since: 0.2
9889  */
9890 void
9891 clutter_actor_get_scale (ClutterActor *self,
9892                          gdouble      *scale_x,
9893                          gdouble      *scale_y)
9894 {
9895   const ClutterTransformInfo *info;
9896
9897   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9898
9899   info = _clutter_actor_get_transform_info_or_defaults (self);
9900
9901   if (scale_x)
9902     *scale_x = info->scale_x;
9903
9904   if (scale_y)
9905     *scale_y = info->scale_y;
9906 }
9907
9908 /**
9909  * clutter_actor_get_scale_center:
9910  * @self: A #ClutterActor
9911  * @center_x: (out) (allow-none): Location to store the X position
9912  *   of the scale center, or %NULL.
9913  * @center_y: (out) (allow-none): Location to store the Y position
9914  *   of the scale center, or %NULL.
9915  *
9916  * Retrieves the scale center coordinate in pixels relative to the top
9917  * left corner of the actor. If the scale center was specified using a
9918  * #ClutterGravity this will calculate the pixel offset using the
9919  * current size of the actor.
9920  *
9921  * Since: 1.0
9922  */
9923 void
9924 clutter_actor_get_scale_center (ClutterActor *self,
9925                                 gfloat       *center_x,
9926                                 gfloat       *center_y)
9927 {
9928   const ClutterTransformInfo *info;
9929
9930   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9931
9932   info = _clutter_actor_get_transform_info_or_defaults (self);
9933
9934   clutter_anchor_coord_get_units (self, &info->scale_center,
9935                                   center_x,
9936                                   center_y,
9937                                   NULL);
9938 }
9939
9940 /**
9941  * clutter_actor_get_scale_gravity:
9942  * @self: A #ClutterActor
9943  *
9944  * Retrieves the scale center as a compass direction. If the scale
9945  * center was specified in pixels or units this will return
9946  * %CLUTTER_GRAVITY_NONE.
9947  *
9948  * Return value: the scale gravity
9949  *
9950  * Since: 1.0
9951  */
9952 ClutterGravity
9953 clutter_actor_get_scale_gravity (ClutterActor *self)
9954 {
9955   const ClutterTransformInfo *info;
9956
9957   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9958
9959   info = _clutter_actor_get_transform_info_or_defaults (self);
9960
9961   return clutter_anchor_coord_get_gravity (&info->scale_center);
9962 }
9963
9964 static inline void
9965 clutter_actor_set_opacity_internal (ClutterActor *self,
9966                                     guint8        opacity)
9967 {
9968   ClutterActorPrivate *priv = self->priv;
9969
9970   if (priv->opacity != opacity)
9971     {
9972       priv->opacity = opacity;
9973
9974       /* Queue a redraw from the flatten effect so that it can use
9975          its cached image if available instead of having to redraw the
9976          actual actor. If it doesn't end up using the FBO then the
9977          effect is still able to continue the paint anyway. If there
9978          is no flatten effect yet then this is equivalent to queueing
9979          a full redraw */
9980       _clutter_actor_queue_redraw_full (self,
9981                                         0, /* flags */
9982                                         NULL, /* clip */
9983                                         priv->flatten_effect);
9984
9985       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9986     }
9987 }
9988
9989 /**
9990  * clutter_actor_set_opacity:
9991  * @self: A #ClutterActor
9992  * @opacity: New opacity value for the actor.
9993  *
9994  * Sets the actor's opacity, with zero being completely transparent and
9995  * 255 (0xff) being fully opaque.
9996  *
9997  * The #ClutterActor:opacity property is animatable.
9998  */
9999 void
10000 clutter_actor_set_opacity (ClutterActor *self,
10001                            guint8        opacity)
10002 {
10003   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10004
10005   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10006     {
10007       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10008                                         self->priv->opacity,
10009                                         opacity);
10010     }
10011   else
10012     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10013
10014   clutter_actor_queue_redraw (self);
10015 }
10016
10017 /*
10018  * clutter_actor_get_paint_opacity_internal:
10019  * @self: a #ClutterActor
10020  *
10021  * Retrieves the absolute opacity of the actor, as it appears on the stage
10022  *
10023  * This function does not do type checks
10024  *
10025  * Return value: the absolute opacity of the actor
10026  */
10027 static guint8
10028 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10029 {
10030   ClutterActorPrivate *priv = self->priv;
10031   ClutterActor *parent;
10032
10033   /* override the top-level opacity to always be 255; even in
10034    * case of ClutterStage:use-alpha being TRUE we want the rest
10035    * of the scene to be painted
10036    */
10037   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10038     return 255;
10039
10040   if (priv->opacity_override >= 0)
10041     return priv->opacity_override;
10042
10043   parent = priv->parent;
10044
10045   /* Factor in the actual actors opacity with parents */
10046   if (parent != NULL)
10047     {
10048       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10049
10050       if (opacity != 0xff)
10051         return (opacity * priv->opacity) / 0xff;
10052     }
10053
10054   return priv->opacity;
10055
10056 }
10057
10058 /**
10059  * clutter_actor_get_paint_opacity:
10060  * @self: A #ClutterActor
10061  *
10062  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10063  *
10064  * This function traverses the hierarchy chain and composites the opacity of
10065  * the actor with that of its parents.
10066  *
10067  * This function is intended for subclasses to use in the paint virtual
10068  * function, to paint themselves with the correct opacity.
10069  *
10070  * Return value: The actor opacity value.
10071  *
10072  * Since: 0.8
10073  */
10074 guint8
10075 clutter_actor_get_paint_opacity (ClutterActor *self)
10076 {
10077   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10078
10079   return clutter_actor_get_paint_opacity_internal (self);
10080 }
10081
10082 /**
10083  * clutter_actor_get_opacity:
10084  * @self: a #ClutterActor
10085  *
10086  * Retrieves the opacity value of an actor, as set by
10087  * clutter_actor_set_opacity().
10088  *
10089  * For retrieving the absolute opacity of the actor inside a paint
10090  * virtual function, see clutter_actor_get_paint_opacity().
10091  *
10092  * Return value: the opacity of the actor
10093  */
10094 guint8
10095 clutter_actor_get_opacity (ClutterActor *self)
10096 {
10097   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10098
10099   return self->priv->opacity;
10100 }
10101
10102 /**
10103  * clutter_actor_set_offscreen_redirect:
10104  * @self: A #ClutterActor
10105  * @redirect: New offscreen redirect flags for the actor.
10106  *
10107  * Defines the circumstances where the actor should be redirected into
10108  * an offscreen image. The offscreen image is used to flatten the
10109  * actor into a single image while painting for two main reasons.
10110  * Firstly, when the actor is painted a second time without any of its
10111  * contents changing it can simply repaint the cached image without
10112  * descending further down the actor hierarchy. Secondly, it will make
10113  * the opacity look correct even if there are overlapping primitives
10114  * in the actor.
10115  *
10116  * Caching the actor could in some cases be a performance win and in
10117  * some cases be a performance lose so it is important to determine
10118  * which value is right for an actor before modifying this value. For
10119  * example, there is never any reason to flatten an actor that is just
10120  * a single texture (such as a #ClutterTexture) because it is
10121  * effectively already cached in an image so the offscreen would be
10122  * redundant. Also if the actor contains primitives that are far apart
10123  * with a large transparent area in the middle (such as a large
10124  * CluterGroup with a small actor in the top left and a small actor in
10125  * the bottom right) then the cached image will contain the entire
10126  * image of the large area and the paint will waste time blending all
10127  * of the transparent pixels in the middle.
10128  *
10129  * The default method of implementing opacity on a container simply
10130  * forwards on the opacity to all of the children. If the children are
10131  * overlapping then it will appear as if they are two separate glassy
10132  * objects and there will be a break in the color where they
10133  * overlap. By redirecting to an offscreen buffer it will be as if the
10134  * two opaque objects are combined into one and then made transparent
10135  * which is usually what is expected.
10136  *
10137  * The image below demonstrates the difference between redirecting and
10138  * not. The image shows two Clutter groups, each containing a red and
10139  * a green rectangle which overlap. The opacity on the group is set to
10140  * 128 (which is 50%). When the offscreen redirect is not used, the
10141  * red rectangle can be seen through the blue rectangle as if the two
10142  * rectangles were separately transparent. When the redirect is used
10143  * the group as a whole is transparent instead so the red rectangle is
10144  * not visible where they overlap.
10145  *
10146  * <figure id="offscreen-redirect">
10147  *   <title>Sample of using an offscreen redirect for transparency</title>
10148  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10149  * </figure>
10150  *
10151  * The default value for this property is 0, so we effectively will
10152  * never redirect an actor offscreen by default. This means that there
10153  * are times that transparent actors may look glassy as described
10154  * above. The reason this is the default is because there is a
10155  * performance trade off between quality and performance here. In many
10156  * cases the default form of glassy opacity looks good enough, but if
10157  * it's not you will need to set the
10158  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10159  * redirection for opacity.
10160  *
10161  * Custom actors that don't contain any overlapping primitives are
10162  * recommended to override the has_overlaps() virtual to return %FALSE
10163  * for maximum efficiency.
10164  *
10165  * Since: 1.8
10166  */
10167 void
10168 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10169                                       ClutterOffscreenRedirect redirect)
10170 {
10171   ClutterActorPrivate *priv;
10172
10173   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10174
10175   priv = self->priv;
10176
10177   if (priv->offscreen_redirect != redirect)
10178     {
10179       priv->offscreen_redirect = redirect;
10180
10181       /* Queue a redraw from the effect so that it can use its cached
10182          image if available instead of having to redraw the actual
10183          actor. If it doesn't end up using the FBO then the effect is
10184          still able to continue the paint anyway. If there is no
10185          effect then this is equivalent to queuing a full redraw */
10186       _clutter_actor_queue_redraw_full (self,
10187                                         0, /* flags */
10188                                         NULL, /* clip */
10189                                         priv->flatten_effect);
10190
10191       g_object_notify_by_pspec (G_OBJECT (self),
10192                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10193     }
10194 }
10195
10196 /**
10197  * clutter_actor_get_offscreen_redirect:
10198  * @self: a #ClutterActor
10199  *
10200  * Retrieves whether to redirect the actor to an offscreen buffer, as
10201  * set by clutter_actor_set_offscreen_redirect().
10202  *
10203  * Return value: the value of the offscreen-redirect property of the actor
10204  *
10205  * Since: 1.8
10206  */
10207 ClutterOffscreenRedirect
10208 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10209 {
10210   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10211
10212   return self->priv->offscreen_redirect;
10213 }
10214
10215 /**
10216  * clutter_actor_set_name:
10217  * @self: A #ClutterActor
10218  * @name: Textual tag to apply to actor
10219  *
10220  * Sets the given name to @self. The name can be used to identify
10221  * a #ClutterActor.
10222  */
10223 void
10224 clutter_actor_set_name (ClutterActor *self,
10225                         const gchar  *name)
10226 {
10227   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10228
10229   g_free (self->priv->name);
10230   self->priv->name = g_strdup (name);
10231
10232   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10233 }
10234
10235 /**
10236  * clutter_actor_get_name:
10237  * @self: A #ClutterActor
10238  *
10239  * Retrieves the name of @self.
10240  *
10241  * Return value: the name of the actor, or %NULL. The returned string is
10242  *   owned by the actor and should not be modified or freed.
10243  */
10244 const gchar *
10245 clutter_actor_get_name (ClutterActor *self)
10246 {
10247   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10248
10249   return self->priv->name;
10250 }
10251
10252 /**
10253  * clutter_actor_get_gid:
10254  * @self: A #ClutterActor
10255  *
10256  * Retrieves the unique id for @self.
10257  *
10258  * Return value: Globally unique value for this object instance.
10259  *
10260  * Since: 0.6
10261  *
10262  * Deprecated: 1.8: The id is not used any longer.
10263  */
10264 guint32
10265 clutter_actor_get_gid (ClutterActor *self)
10266 {
10267   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10268
10269   return self->priv->id;
10270 }
10271
10272 static inline void
10273 clutter_actor_set_depth_internal (ClutterActor *self,
10274                                   float         depth)
10275 {
10276   ClutterTransformInfo *info;
10277
10278   info = _clutter_actor_get_transform_info (self);
10279
10280   if (info->depth != depth)
10281     {
10282       /* Sets Z value - XXX 2.0: should we invert? */
10283       info->depth = depth;
10284
10285       self->priv->transform_valid = FALSE;
10286
10287       /* FIXME - remove this crap; sadly, there are still containers
10288        * in Clutter that depend on this utter brain damage
10289        */
10290       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10291
10292       clutter_actor_queue_redraw (self);
10293
10294       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10295     }
10296 }
10297
10298 /**
10299  * clutter_actor_set_depth:
10300  * @self: a #ClutterActor
10301  * @depth: Z co-ord
10302  *
10303  * Sets the Z coordinate of @self to @depth.
10304  *
10305  * The unit used by @depth is dependant on the perspective setup. See
10306  * also clutter_stage_set_perspective().
10307  */
10308 void
10309 clutter_actor_set_depth (ClutterActor *self,
10310                          gfloat        depth)
10311 {
10312   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10313
10314   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10315     {
10316       const ClutterTransformInfo *info;
10317
10318       info = _clutter_actor_get_transform_info_or_defaults (self);
10319
10320       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10321                                         info->depth,
10322                                         depth);
10323     }
10324   else
10325     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10326
10327   clutter_actor_queue_redraw (self);
10328 }
10329
10330 /**
10331  * clutter_actor_get_depth:
10332  * @self: a #ClutterActor
10333  *
10334  * Retrieves the depth of @self.
10335  *
10336  * Return value: the depth of the actor
10337  */
10338 gfloat
10339 clutter_actor_get_depth (ClutterActor *self)
10340 {
10341   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10342
10343   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10344 }
10345
10346 /**
10347  * clutter_actor_set_rotation:
10348  * @self: a #ClutterActor
10349  * @axis: the axis of rotation
10350  * @angle: the angle of rotation
10351  * @x: X coordinate of the rotation center
10352  * @y: Y coordinate of the rotation center
10353  * @z: Z coordinate of the rotation center
10354  *
10355  * Sets the rotation angle of @self around the given axis.
10356  *
10357  * The rotation center coordinates used depend on the value of @axis:
10358  * <itemizedlist>
10359  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10360  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10361  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10362  * </itemizedlist>
10363  *
10364  * The rotation coordinates are relative to the anchor point of the
10365  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10366  * point is set, the upper left corner is assumed as the origin.
10367  *
10368  * Since: 0.8
10369  */
10370 void
10371 clutter_actor_set_rotation (ClutterActor      *self,
10372                             ClutterRotateAxis  axis,
10373                             gdouble            angle,
10374                             gfloat             x,
10375                             gfloat             y,
10376                             gfloat             z)
10377 {
10378   ClutterVertex v;
10379
10380   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10381
10382   v.x = x;
10383   v.y = y;
10384   v.z = z;
10385
10386   g_object_freeze_notify (G_OBJECT (self));
10387
10388   clutter_actor_set_rotation_angle (self, axis, angle);
10389   clutter_actor_set_rotation_center_internal (self, axis, &v);
10390
10391   g_object_thaw_notify (G_OBJECT (self));
10392 }
10393
10394 /**
10395  * clutter_actor_set_z_rotation_from_gravity:
10396  * @self: a #ClutterActor
10397  * @angle: the angle of rotation
10398  * @gravity: the center point of the rotation
10399  *
10400  * Sets the rotation angle of @self around the Z axis using the center
10401  * point specified as a compass point. For example to rotate such that
10402  * the center of the actor remains static you can use
10403  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10404  * will move accordingly.
10405  *
10406  * Since: 1.0
10407  */
10408 void
10409 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10410                                            gdouble         angle,
10411                                            ClutterGravity  gravity)
10412 {
10413   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10414
10415   if (gravity == CLUTTER_GRAVITY_NONE)
10416     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10417   else
10418     {
10419       GObject *obj = G_OBJECT (self);
10420       ClutterTransformInfo *info;
10421
10422       info = _clutter_actor_get_transform_info (self);
10423
10424       g_object_freeze_notify (obj);
10425
10426       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10427
10428       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10429       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10430       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10431
10432       g_object_thaw_notify (obj);
10433     }
10434 }
10435
10436 /**
10437  * clutter_actor_get_rotation:
10438  * @self: a #ClutterActor
10439  * @axis: the axis of rotation
10440  * @x: (out): return value for the X coordinate of the center of rotation
10441  * @y: (out): return value for the Y coordinate of the center of rotation
10442  * @z: (out): return value for the Z coordinate of the center of rotation
10443  *
10444  * Retrieves the angle and center of rotation on the given axis,
10445  * set using clutter_actor_set_rotation().
10446  *
10447  * Return value: the angle of rotation
10448  *
10449  * Since: 0.8
10450  */
10451 gdouble
10452 clutter_actor_get_rotation (ClutterActor      *self,
10453                             ClutterRotateAxis  axis,
10454                             gfloat            *x,
10455                             gfloat            *y,
10456                             gfloat            *z)
10457 {
10458   const ClutterTransformInfo *info;
10459   const AnchorCoord *anchor_coord;
10460   gdouble retval = 0;
10461
10462   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10463
10464   info = _clutter_actor_get_transform_info_or_defaults (self);
10465
10466   switch (axis)
10467     {
10468     case CLUTTER_X_AXIS:
10469       anchor_coord = &info->rx_center;
10470       retval = info->rx_angle;
10471       break;
10472
10473     case CLUTTER_Y_AXIS:
10474       anchor_coord = &info->ry_center;
10475       retval = info->ry_angle;
10476       break;
10477
10478     case CLUTTER_Z_AXIS:
10479       anchor_coord = &info->rz_center;
10480       retval = info->rz_angle;
10481       break;
10482
10483     default:
10484       anchor_coord = NULL;
10485       retval = 0.0;
10486       break;
10487     }
10488
10489   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10490
10491   return retval;
10492 }
10493
10494 /**
10495  * clutter_actor_get_z_rotation_gravity:
10496  * @self: A #ClutterActor
10497  *
10498  * Retrieves the center for the rotation around the Z axis as a
10499  * compass direction. If the center was specified in pixels or units
10500  * this will return %CLUTTER_GRAVITY_NONE.
10501  *
10502  * Return value: the Z rotation center
10503  *
10504  * Since: 1.0
10505  */
10506 ClutterGravity
10507 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10508 {
10509   const ClutterTransformInfo *info;
10510
10511   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10512
10513   info = _clutter_actor_get_transform_info_or_defaults (self);
10514
10515   return clutter_anchor_coord_get_gravity (&info->rz_center);
10516 }
10517
10518 /**
10519  * clutter_actor_set_clip:
10520  * @self: A #ClutterActor
10521  * @xoff: X offset of the clip rectangle
10522  * @yoff: Y offset of the clip rectangle
10523  * @width: Width of the clip rectangle
10524  * @height: Height of the clip rectangle
10525  *
10526  * Sets clip area for @self. The clip area is always computed from the
10527  * upper left corner of the actor, even if the anchor point is set
10528  * otherwise.
10529  *
10530  * Since: 0.6
10531  */
10532 void
10533 clutter_actor_set_clip (ClutterActor *self,
10534                         gfloat        xoff,
10535                         gfloat        yoff,
10536                         gfloat        width,
10537                         gfloat        height)
10538 {
10539   ClutterActorPrivate *priv;
10540
10541   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10542
10543   priv = self->priv;
10544
10545   if (priv->has_clip &&
10546       priv->clip.x == xoff &&
10547       priv->clip.y == yoff &&
10548       priv->clip.width == width &&
10549       priv->clip.height == height)
10550     return;
10551
10552   priv->clip.x = xoff;
10553   priv->clip.y = yoff;
10554   priv->clip.width = width;
10555   priv->clip.height = height;
10556
10557   priv->has_clip = TRUE;
10558
10559   clutter_actor_queue_redraw (self);
10560
10561   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10562   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10563 }
10564
10565 /**
10566  * clutter_actor_remove_clip:
10567  * @self: A #ClutterActor
10568  *
10569  * Removes clip area from @self.
10570  */
10571 void
10572 clutter_actor_remove_clip (ClutterActor *self)
10573 {
10574   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10575
10576   if (!self->priv->has_clip)
10577     return;
10578
10579   self->priv->has_clip = FALSE;
10580
10581   clutter_actor_queue_redraw (self);
10582
10583   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10584 }
10585
10586 /**
10587  * clutter_actor_has_clip:
10588  * @self: a #ClutterActor
10589  *
10590  * Determines whether the actor has a clip area set or not.
10591  *
10592  * Return value: %TRUE if the actor has a clip area set.
10593  *
10594  * Since: 0.1.1
10595  */
10596 gboolean
10597 clutter_actor_has_clip (ClutterActor *self)
10598 {
10599   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10600
10601   return self->priv->has_clip;
10602 }
10603
10604 /**
10605  * clutter_actor_get_clip:
10606  * @self: a #ClutterActor
10607  * @xoff: (out) (allow-none): return location for the X offset of
10608  *   the clip rectangle, or %NULL
10609  * @yoff: (out) (allow-none): return location for the Y offset of
10610  *   the clip rectangle, or %NULL
10611  * @width: (out) (allow-none): return location for the width of
10612  *   the clip rectangle, or %NULL
10613  * @height: (out) (allow-none): return location for the height of
10614  *   the clip rectangle, or %NULL
10615  *
10616  * Gets the clip area for @self, if any is set
10617  *
10618  * Since: 0.6
10619  */
10620 void
10621 clutter_actor_get_clip (ClutterActor *self,
10622                         gfloat       *xoff,
10623                         gfloat       *yoff,
10624                         gfloat       *width,
10625                         gfloat       *height)
10626 {
10627   ClutterActorPrivate *priv;
10628
10629   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10630
10631   priv = self->priv;
10632
10633   if (!priv->has_clip)
10634     return;
10635
10636   if (xoff != NULL)
10637     *xoff = priv->clip.x;
10638
10639   if (yoff != NULL)
10640     *yoff = priv->clip.y;
10641
10642   if (width != NULL)
10643     *width = priv->clip.width;
10644
10645   if (height != NULL)
10646     *height = priv->clip.height;
10647 }
10648
10649 /**
10650  * clutter_actor_get_children:
10651  * @self: a #ClutterActor
10652  *
10653  * Retrieves the list of children of @self.
10654  *
10655  * Return value: (transfer container) (element-type ClutterActor): A newly
10656  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10657  *   done.
10658  *
10659  * Since: 1.10
10660  */
10661 GList *
10662 clutter_actor_get_children (ClutterActor *self)
10663 {
10664   ClutterActor *iter;
10665   GList *res;
10666
10667   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10668
10669   /* we walk the list backward so that we can use prepend(),
10670    * which is O(1)
10671    */
10672   for (iter = self->priv->last_child, res = NULL;
10673        iter != NULL;
10674        iter = iter->priv->prev_sibling)
10675     {
10676       res = g_list_prepend (res, iter);
10677     }
10678
10679   return res;
10680 }
10681
10682 /*< private >
10683  * insert_child_at_depth:
10684  * @self: a #ClutterActor
10685  * @child: a #ClutterActor
10686  *
10687  * Inserts @child inside the list of children held by @self, using
10688  * the depth as the insertion criteria.
10689  *
10690  * This sadly makes the insertion not O(1), but we can keep the
10691  * list sorted so that the painters algorithm we use for painting
10692  * the children will work correctly.
10693  */
10694 static void
10695 insert_child_at_depth (ClutterActor *self,
10696                        ClutterActor *child,
10697                        gpointer      dummy G_GNUC_UNUSED)
10698 {
10699   ClutterActor *iter;
10700   float child_depth;
10701
10702   child->priv->parent = self;
10703
10704   child_depth =
10705     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10706
10707   /* special-case the first child */
10708   if (self->priv->n_children == 0)
10709     {
10710       self->priv->first_child = child;
10711       self->priv->last_child = child;
10712
10713       child->priv->next_sibling = NULL;
10714       child->priv->prev_sibling = NULL;
10715
10716       return;
10717     }
10718
10719   /* Find the right place to insert the child so that it will still be
10720      sorted and the child will be after all of the actors at the same
10721      dept */
10722   for (iter = self->priv->first_child;
10723        iter != NULL;
10724        iter = iter->priv->next_sibling)
10725     {
10726       float iter_depth;
10727
10728       iter_depth =
10729         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10730
10731       if (iter_depth > child_depth)
10732         break;
10733     }
10734
10735   if (iter != NULL)
10736     {
10737       ClutterActor *tmp = iter->priv->prev_sibling;
10738
10739       if (tmp != NULL)
10740         tmp->priv->next_sibling = child;
10741
10742       /* Insert the node before the found one */
10743       child->priv->prev_sibling = iter->priv->prev_sibling;
10744       child->priv->next_sibling = iter;
10745       iter->priv->prev_sibling = child;
10746     }
10747   else
10748     {
10749       ClutterActor *tmp = self->priv->last_child;
10750
10751       if (tmp != NULL)
10752         tmp->priv->next_sibling = child;
10753
10754       /* insert the node at the end of the list */
10755       child->priv->prev_sibling = self->priv->last_child;
10756       child->priv->next_sibling = NULL;
10757     }
10758
10759   if (child->priv->prev_sibling == NULL)
10760     self->priv->first_child = child;
10761
10762   if (child->priv->next_sibling == NULL)
10763     self->priv->last_child = child;
10764 }
10765
10766 static void
10767 insert_child_at_index (ClutterActor *self,
10768                        ClutterActor *child,
10769                        gpointer      data_)
10770 {
10771   gint index_ = GPOINTER_TO_INT (data_);
10772
10773   child->priv->parent = self;
10774
10775   if (index_ == 0)
10776     {
10777       ClutterActor *tmp = self->priv->first_child;
10778
10779       if (tmp != NULL)
10780         tmp->priv->prev_sibling = child;
10781
10782       child->priv->prev_sibling = NULL;
10783       child->priv->next_sibling = tmp;
10784     }
10785   else if (index_ < 0 || index_ >= self->priv->n_children)
10786     {
10787       ClutterActor *tmp = self->priv->last_child;
10788
10789       if (tmp != NULL)
10790         tmp->priv->next_sibling = child;
10791
10792       child->priv->prev_sibling = tmp;
10793       child->priv->next_sibling = NULL;
10794     }
10795   else
10796     {
10797       ClutterActor *iter;
10798       int i;
10799
10800       for (iter = self->priv->first_child, i = 0;
10801            iter != NULL;
10802            iter = iter->priv->next_sibling, i += 1)
10803         {
10804           if (index_ == i)
10805             {
10806               ClutterActor *tmp = iter->priv->prev_sibling;
10807
10808               child->priv->prev_sibling = tmp;
10809               child->priv->next_sibling = iter;
10810
10811               iter->priv->prev_sibling = child;
10812
10813               if (tmp != NULL)
10814                 tmp->priv->next_sibling = child;
10815
10816               break;
10817             }
10818         }
10819     }
10820
10821   if (child->priv->prev_sibling == NULL)
10822     self->priv->first_child = child;
10823
10824   if (child->priv->next_sibling == NULL)
10825     self->priv->last_child = child;
10826 }
10827
10828 static void
10829 insert_child_above (ClutterActor *self,
10830                     ClutterActor *child,
10831                     gpointer      data)
10832 {
10833   ClutterActor *sibling = data;
10834
10835   child->priv->parent = self;
10836
10837   if (sibling == NULL)
10838     sibling = self->priv->last_child;
10839
10840   child->priv->prev_sibling = sibling;
10841
10842   if (sibling != NULL)
10843     {
10844       ClutterActor *tmp = sibling->priv->next_sibling;
10845
10846       child->priv->next_sibling = tmp;
10847
10848       if (tmp != NULL)
10849         tmp->priv->prev_sibling = child;
10850
10851       sibling->priv->next_sibling = child;
10852     }
10853   else
10854     child->priv->next_sibling = NULL;
10855
10856   if (child->priv->prev_sibling == NULL)
10857     self->priv->first_child = child;
10858
10859   if (child->priv->next_sibling == NULL)
10860     self->priv->last_child = child;
10861 }
10862
10863 static void
10864 insert_child_below (ClutterActor *self,
10865                     ClutterActor *child,
10866                     gpointer      data)
10867 {
10868   ClutterActor *sibling = data;
10869
10870   child->priv->parent = self;
10871
10872   if (sibling == NULL)
10873     sibling = self->priv->first_child;
10874
10875   child->priv->next_sibling = sibling;
10876
10877   if (sibling != NULL)
10878     {
10879       ClutterActor *tmp = sibling->priv->prev_sibling;
10880
10881       child->priv->prev_sibling = tmp;
10882
10883       if (tmp != NULL)
10884         tmp->priv->next_sibling = child;
10885
10886       sibling->priv->prev_sibling = child;
10887     }
10888   else
10889     child->priv->prev_sibling = NULL;
10890
10891   if (child->priv->prev_sibling == NULL)
10892     self->priv->first_child = child;
10893
10894   if (child->priv->next_sibling == NULL)
10895     self->priv->last_child = child;
10896 }
10897
10898 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10899                                            ClutterActor *child,
10900                                            gpointer      data);
10901
10902 typedef enum {
10903   ADD_CHILD_CREATE_META       = 1 << 0,
10904   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10905   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10906   ADD_CHILD_CHECK_STATE       = 1 << 3,
10907   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10908
10909   /* default flags for public API */
10910   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10911                                ADD_CHILD_EMIT_PARENT_SET |
10912                                ADD_CHILD_EMIT_ACTOR_ADDED |
10913                                ADD_CHILD_CHECK_STATE |
10914                                ADD_CHILD_NOTIFY_FIRST_LAST,
10915
10916   /* flags for legacy/deprecated API */
10917   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10918                                ADD_CHILD_CHECK_STATE |
10919                                ADD_CHILD_NOTIFY_FIRST_LAST
10920 } ClutterActorAddChildFlags;
10921
10922 /*< private >
10923  * clutter_actor_add_child_internal:
10924  * @self: a #ClutterActor
10925  * @child: a #ClutterActor
10926  * @flags: control flags for actions
10927  * @add_func: delegate function
10928  * @data: (closure): data to pass to @add_func
10929  *
10930  * Adds @child to the list of children of @self.
10931  *
10932  * The actual insertion inside the list is delegated to @add_func: this
10933  * function will just set up the state, perform basic checks, and emit
10934  * signals.
10935  *
10936  * The @flags argument is used to perform additional operations.
10937  */
10938 static inline void
10939 clutter_actor_add_child_internal (ClutterActor              *self,
10940                                   ClutterActor              *child,
10941                                   ClutterActorAddChildFlags  flags,
10942                                   ClutterActorAddChildFunc   add_func,
10943                                   gpointer                   data)
10944 {
10945   ClutterTextDirection text_dir;
10946   gboolean create_meta;
10947   gboolean emit_parent_set, emit_actor_added;
10948   gboolean check_state;
10949   gboolean notify_first_last;
10950   ClutterActor *old_first_child, *old_last_child;
10951
10952   if (child->priv->parent != NULL)
10953     {
10954       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10955                  "use clutter_actor_remove_child() first.",
10956                  _clutter_actor_get_debug_name (child),
10957                  _clutter_actor_get_debug_name (child->priv->parent));
10958       return;
10959     }
10960
10961   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10962     {
10963       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10964                  "a child of another actor.",
10965                  _clutter_actor_get_debug_name (child));
10966       return;
10967     }
10968
10969 #if 0
10970   /* XXX - this check disallows calling methods that change the stacking
10971    * order within the destruction sequence, by triggering a critical
10972    * warning first, and leaving the actor in an undefined state, which
10973    * then ends up being caught by an assertion.
10974    *
10975    * the reproducible sequence is:
10976    *
10977    *   - actor gets destroyed;
10978    *   - another actor, linked to the first, will try to change the
10979    *     stacking order of the first actor;
10980    *   - changing the stacking order is a composite operation composed
10981    *     by the following steps:
10982    *     1. ref() the child;
10983    *     2. remove_child_internal(), which removes the reference;
10984    *     3. add_child_internal(), which adds a reference;
10985    *   - the state of the actor is not changed between (2) and (3), as
10986    *     it could be an expensive recomputation;
10987    *   - if (3) bails out, then the actor is in an undefined state, but
10988    *     still alive;
10989    *   - the destruction sequence terminates, but the actor is unparented
10990    *     while its state indicates being parented instead.
10991    *   - assertion failure.
10992    *
10993    * the obvious fix would be to decompose each set_child_*_sibling()
10994    * method into proper remove_child()/add_child(), with state validation;
10995    * this may cause excessive work, though, and trigger a cascade of other
10996    * bugs in code that assumes that a change in the stacking order is an
10997    * atomic operation.
10998    *
10999    * another potential fix is to just remove this check here, and let
11000    * code doing stacking order changes inside the destruction sequence
11001    * of an actor continue doing the work.
11002    *
11003    * the third fix is to silently bail out early from every
11004    * set_child_*_sibling() and set_child_at_index() method, and avoid
11005    * doing work.
11006    *
11007    * I have a preference for the second solution, since it involves the
11008    * least amount of work, and the least amount of code duplication.
11009    *
11010    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11011    */
11012   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11013     {
11014       g_warning ("The actor '%s' is currently being destroyed, and "
11015                  "cannot be added as a child of another actor.",
11016                  _clutter_actor_get_debug_name (child));
11017       return;
11018     }
11019 #endif
11020
11021   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11022   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11023   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11024   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11025   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11026
11027   old_first_child = self->priv->first_child;
11028   old_last_child = self->priv->last_child;
11029
11030   g_object_freeze_notify (G_OBJECT (self));
11031
11032   if (create_meta)
11033     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11034
11035   g_object_ref_sink (child);
11036   child->priv->parent = NULL;
11037   child->priv->next_sibling = NULL;
11038   child->priv->prev_sibling = NULL;
11039
11040   /* delegate the actual insertion */
11041   add_func (self, child, data);
11042
11043   g_assert (child->priv->parent == self);
11044
11045   self->priv->n_children += 1;
11046
11047   self->priv->age += 1;
11048
11049   /* if push_internal() has been called then we automatically set
11050    * the flag on the actor
11051    */
11052   if (self->priv->internal_child)
11053     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11054
11055   /* clutter_actor_reparent() will emit ::parent-set for us */
11056   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11057     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11058
11059   if (check_state)
11060     {
11061       /* If parent is mapped or realized, we need to also be mapped or
11062        * realized once we're inside the parent.
11063        */
11064       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11065
11066       /* propagate the parent's text direction to the child */
11067       text_dir = clutter_actor_get_text_direction (self);
11068       clutter_actor_set_text_direction (child, text_dir);
11069     }
11070
11071   if (child->priv->show_on_set_parent)
11072     clutter_actor_show (child);
11073
11074   if (CLUTTER_ACTOR_IS_MAPPED (child))
11075     clutter_actor_queue_redraw (child);
11076
11077   /* maintain the invariant that if an actor needs layout,
11078    * its parents do as well
11079    */
11080   if (child->priv->needs_width_request ||
11081       child->priv->needs_height_request ||
11082       child->priv->needs_allocation)
11083     {
11084       /* we work around the short-circuiting we do
11085        * in clutter_actor_queue_relayout() since we
11086        * want to force a relayout
11087        */
11088       child->priv->needs_width_request = TRUE;
11089       child->priv->needs_height_request = TRUE;
11090       child->priv->needs_allocation = TRUE;
11091
11092       clutter_actor_queue_relayout (child->priv->parent);
11093     }
11094
11095   if (emit_actor_added)
11096     g_signal_emit_by_name (self, "actor-added", child);
11097
11098   if (notify_first_last)
11099     {
11100       if (old_first_child != self->priv->first_child)
11101         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11102
11103       if (old_last_child != self->priv->last_child)
11104         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11105     }
11106
11107   g_object_thaw_notify (G_OBJECT (self));
11108 }
11109
11110 /**
11111  * clutter_actor_add_child:
11112  * @self: a #ClutterActor
11113  * @child: a #ClutterActor
11114  *
11115  * Adds @child to the children of @self.
11116  *
11117  * This function will acquire a reference on @child that will only
11118  * be released when calling clutter_actor_remove_child().
11119  *
11120  * This function will take into consideration the #ClutterActor:depth
11121  * of @child, and will keep the list of children sorted.
11122  *
11123  * This function will emit the #ClutterContainer::actor-added signal
11124  * on @self.
11125  *
11126  * Since: 1.10
11127  */
11128 void
11129 clutter_actor_add_child (ClutterActor *self,
11130                          ClutterActor *child)
11131 {
11132   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11133   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11134   g_return_if_fail (self != child);
11135   g_return_if_fail (child->priv->parent == NULL);
11136
11137   clutter_actor_add_child_internal (self, child,
11138                                     ADD_CHILD_DEFAULT_FLAGS,
11139                                     insert_child_at_depth,
11140                                     NULL);
11141 }
11142
11143 /**
11144  * clutter_actor_insert_child_at_index:
11145  * @self: a #ClutterActor
11146  * @child: a #ClutterActor
11147  * @index_: the index
11148  *
11149  * Inserts @child into the list of children of @self, using the
11150  * given @index_. If @index_ is greater than the number of children
11151  * in @self, or is less than 0, then the new child is added at the end.
11152  *
11153  * This function will acquire a reference on @child that will only
11154  * be released when calling clutter_actor_remove_child().
11155  *
11156  * This function will not take into consideration the #ClutterActor:depth
11157  * of @child.
11158  *
11159  * This function will emit the #ClutterContainer::actor-added signal
11160  * on @self.
11161  *
11162  * Since: 1.10
11163  */
11164 void
11165 clutter_actor_insert_child_at_index (ClutterActor *self,
11166                                      ClutterActor *child,
11167                                      gint          index_)
11168 {
11169   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11170   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11171   g_return_if_fail (self != child);
11172   g_return_if_fail (child->priv->parent == NULL);
11173
11174   clutter_actor_add_child_internal (self, child,
11175                                     ADD_CHILD_DEFAULT_FLAGS,
11176                                     insert_child_at_index,
11177                                     GINT_TO_POINTER (index_));
11178 }
11179
11180 /**
11181  * clutter_actor_insert_child_above:
11182  * @self: a #ClutterActor
11183  * @child: a #ClutterActor
11184  * @sibling: (allow-none): a child of @self, or %NULL
11185  *
11186  * Inserts @child into the list of children of @self, above another
11187  * child of @self or, if @sibling is %NULL, above all the children
11188  * of @self.
11189  *
11190  * This function will acquire a reference on @child that will only
11191  * be released when calling clutter_actor_remove_child().
11192  *
11193  * This function will not take into consideration the #ClutterActor:depth
11194  * of @child.
11195  *
11196  * This function will emit the #ClutterContainer::actor-added signal
11197  * on @self.
11198  *
11199  * Since: 1.10
11200  */
11201 void
11202 clutter_actor_insert_child_above (ClutterActor *self,
11203                                   ClutterActor *child,
11204                                   ClutterActor *sibling)
11205 {
11206   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11207   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11208   g_return_if_fail (self != child);
11209   g_return_if_fail (child != sibling);
11210   g_return_if_fail (child->priv->parent == NULL);
11211   g_return_if_fail (sibling == NULL ||
11212                     (CLUTTER_IS_ACTOR (sibling) &&
11213                      sibling->priv->parent == self));
11214
11215   clutter_actor_add_child_internal (self, child,
11216                                     ADD_CHILD_DEFAULT_FLAGS,
11217                                     insert_child_above,
11218                                     sibling);
11219 }
11220
11221 /**
11222  * clutter_actor_insert_child_below:
11223  * @self: a #ClutterActor
11224  * @child: a #ClutterActor
11225  * @sibling: (allow-none): a child of @self, or %NULL
11226  *
11227  * Inserts @child into the list of children of @self, below another
11228  * child of @self or, if @sibling is %NULL, below all the children
11229  * of @self.
11230  *
11231  * This function will acquire a reference on @child that will only
11232  * be released when calling clutter_actor_remove_child().
11233  *
11234  * This function will not take into consideration the #ClutterActor:depth
11235  * of @child.
11236  *
11237  * This function will emit the #ClutterContainer::actor-added signal
11238  * on @self.
11239  *
11240  * Since: 1.10
11241  */
11242 void
11243 clutter_actor_insert_child_below (ClutterActor *self,
11244                                   ClutterActor *child,
11245                                   ClutterActor *sibling)
11246 {
11247   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11248   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11249   g_return_if_fail (self != child);
11250   g_return_if_fail (child != sibling);
11251   g_return_if_fail (child->priv->parent == NULL);
11252   g_return_if_fail (sibling == NULL ||
11253                     (CLUTTER_IS_ACTOR (sibling) &&
11254                      sibling->priv->parent == self));
11255
11256   clutter_actor_add_child_internal (self, child,
11257                                     ADD_CHILD_DEFAULT_FLAGS,
11258                                     insert_child_below,
11259                                     sibling);
11260 }
11261
11262 /**
11263  * clutter_actor_set_parent:
11264  * @self: A #ClutterActor
11265  * @parent: A new #ClutterActor parent
11266  *
11267  * Sets the parent of @self to @parent.
11268  *
11269  * This function will result in @parent acquiring a reference on @self,
11270  * eventually by sinking its floating reference first. The reference
11271  * will be released by clutter_actor_unparent().
11272  *
11273  * This function should only be called by legacy #ClutterActor<!-- -->s
11274  * implementing the #ClutterContainer interface.
11275  *
11276  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11277  */
11278 void
11279 clutter_actor_set_parent (ClutterActor *self,
11280                           ClutterActor *parent)
11281 {
11282   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11283   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11284   g_return_if_fail (self != parent);
11285   g_return_if_fail (self->priv->parent == NULL);
11286
11287   /* as this function will be called inside ClutterContainer::add
11288    * implementations or when building up a composite actor, we have
11289    * to preserve the old behaviour, and not create child meta or
11290    * emit the ::actor-added signal, to avoid recursion or double
11291    * emissions
11292    */
11293   clutter_actor_add_child_internal (parent, self,
11294                                     ADD_CHILD_LEGACY_FLAGS,
11295                                     insert_child_at_depth,
11296                                     NULL);
11297 }
11298
11299 /**
11300  * clutter_actor_get_parent:
11301  * @self: A #ClutterActor
11302  *
11303  * Retrieves the parent of @self.
11304  *
11305  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11306  *  if no parent is set
11307  */
11308 ClutterActor *
11309 clutter_actor_get_parent (ClutterActor *self)
11310 {
11311   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11312
11313   return self->priv->parent;
11314 }
11315
11316 /**
11317  * clutter_actor_get_paint_visibility:
11318  * @self: A #ClutterActor
11319  *
11320  * Retrieves the 'paint' visibility of an actor recursively checking for non
11321  * visible parents.
11322  *
11323  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11324  *
11325  * Return Value: %TRUE if the actor is visibile and will be painted.
11326  *
11327  * Since: 0.8.4
11328  */
11329 gboolean
11330 clutter_actor_get_paint_visibility (ClutterActor *actor)
11331 {
11332   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11333
11334   return CLUTTER_ACTOR_IS_MAPPED (actor);
11335 }
11336
11337 /**
11338  * clutter_actor_remove_child:
11339  * @self: a #ClutterActor
11340  * @child: a #ClutterActor
11341  *
11342  * Removes @child from the children of @self.
11343  *
11344  * This function will release the reference added by
11345  * clutter_actor_add_child(), so if you want to keep using @child
11346  * you will have to acquire a referenced on it before calling this
11347  * function.
11348  *
11349  * This function will emit the #ClutterContainer::actor-removed
11350  * signal on @self.
11351  *
11352  * Since: 1.10
11353  */
11354 void
11355 clutter_actor_remove_child (ClutterActor *self,
11356                             ClutterActor *child)
11357 {
11358   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11359   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11360   g_return_if_fail (self != child);
11361   g_return_if_fail (child->priv->parent != NULL);
11362   g_return_if_fail (child->priv->parent == self);
11363
11364   clutter_actor_remove_child_internal (self, child,
11365                                        REMOVE_CHILD_DEFAULT_FLAGS);
11366 }
11367
11368 /**
11369  * clutter_actor_remove_all_children:
11370  * @self: a #ClutterActor
11371  *
11372  * Removes all children of @self.
11373  *
11374  * This function releases the reference added by inserting a child actor
11375  * in the list of children of @self.
11376  *
11377  * If the reference count of a child drops to zero, the child will be
11378  * destroyed. If you want to ensure the destruction of all the children
11379  * of @self, use clutter_actor_destroy_all_children().
11380  *
11381  * Since: 1.10
11382  */
11383 void
11384 clutter_actor_remove_all_children (ClutterActor *self)
11385 {
11386   ClutterActorIter iter;
11387
11388   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11389
11390   if (self->priv->n_children == 0)
11391     return;
11392
11393   g_object_freeze_notify (G_OBJECT (self));
11394
11395   clutter_actor_iter_init (&iter, self);
11396   while (clutter_actor_iter_next (&iter, NULL))
11397     clutter_actor_iter_remove (&iter);
11398
11399   g_object_thaw_notify (G_OBJECT (self));
11400
11401   /* sanity check */
11402   g_assert (self->priv->first_child == NULL);
11403   g_assert (self->priv->last_child == NULL);
11404   g_assert (self->priv->n_children == 0);
11405 }
11406
11407 /**
11408  * clutter_actor_destroy_all_children:
11409  * @self: a #ClutterActor
11410  *
11411  * Destroys all children of @self.
11412  *
11413  * This function releases the reference added by inserting a child
11414  * actor in the list of children of @self, and ensures that the
11415  * #ClutterActor::destroy signal is emitted on each child of the
11416  * actor.
11417  *
11418  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11419  * when its reference count drops to 0; the default handler of the
11420  * #ClutterActor::destroy signal will destroy all the children of an
11421  * actor. This function ensures that all children are destroyed, instead
11422  * of just removed from @self, unlike clutter_actor_remove_all_children()
11423  * which will merely release the reference and remove each child.
11424  *
11425  * Unless you acquired an additional reference on each child of @self
11426  * prior to calling clutter_actor_remove_all_children() and want to reuse
11427  * the actors, you should use clutter_actor_destroy_all_children() in
11428  * order to make sure that children are destroyed and signal handlers
11429  * are disconnected even in cases where circular references prevent this
11430  * from automatically happening through reference counting alone.
11431  *
11432  * Since: 1.10
11433  */
11434 void
11435 clutter_actor_destroy_all_children (ClutterActor *self)
11436 {
11437   ClutterActorIter iter;
11438
11439   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11440
11441   if (self->priv->n_children == 0)
11442     return;
11443
11444   g_object_freeze_notify (G_OBJECT (self));
11445
11446   clutter_actor_iter_init (&iter, self);
11447   while (clutter_actor_iter_next (&iter, NULL))
11448     clutter_actor_iter_destroy (&iter);
11449
11450   g_object_thaw_notify (G_OBJECT (self));
11451
11452   /* sanity check */
11453   g_assert (self->priv->first_child == NULL);
11454   g_assert (self->priv->last_child == NULL);
11455   g_assert (self->priv->n_children == 0);
11456 }
11457
11458 typedef struct _InsertBetweenData {
11459   ClutterActor *prev_sibling;
11460   ClutterActor *next_sibling;
11461 } InsertBetweenData;
11462
11463 static void
11464 insert_child_between (ClutterActor *self,
11465                       ClutterActor *child,
11466                       gpointer      data_)
11467 {
11468   InsertBetweenData *data = data_;
11469   ClutterActor *prev_sibling = data->prev_sibling;
11470   ClutterActor *next_sibling = data->next_sibling;
11471
11472   child->priv->parent = self;
11473   child->priv->prev_sibling = prev_sibling;
11474   child->priv->next_sibling = next_sibling;
11475
11476   if (prev_sibling != NULL)
11477     prev_sibling->priv->next_sibling = child;
11478
11479   if (next_sibling != NULL)
11480     next_sibling->priv->prev_sibling = child;
11481
11482   if (child->priv->prev_sibling == NULL)
11483     self->priv->first_child = child;
11484
11485   if (child->priv->next_sibling == NULL)
11486     self->priv->last_child = child;
11487 }
11488
11489 /**
11490  * clutter_actor_replace_child:
11491  * @self: a #ClutterActor
11492  * @old_child: the child of @self to replace
11493  * @new_child: the #ClutterActor to replace @old_child
11494  *
11495  * Replaces @old_child with @new_child in the list of children of @self.
11496  *
11497  * Since: 1.10
11498  */
11499 void
11500 clutter_actor_replace_child (ClutterActor *self,
11501                              ClutterActor *old_child,
11502                              ClutterActor *new_child)
11503 {
11504   ClutterActor *prev_sibling, *next_sibling;
11505   InsertBetweenData clos;
11506
11507   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11508   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11509   g_return_if_fail (old_child->priv->parent == self);
11510   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11511   g_return_if_fail (old_child != new_child);
11512   g_return_if_fail (new_child != self);
11513   g_return_if_fail (new_child->priv->parent == NULL);
11514
11515   prev_sibling = old_child->priv->prev_sibling;
11516   next_sibling = old_child->priv->next_sibling;
11517   clutter_actor_remove_child_internal (self, old_child,
11518                                        REMOVE_CHILD_DEFAULT_FLAGS);
11519
11520   clos.prev_sibling = prev_sibling;
11521   clos.next_sibling = next_sibling;
11522   clutter_actor_add_child_internal (self, new_child,
11523                                     ADD_CHILD_DEFAULT_FLAGS,
11524                                     insert_child_between,
11525                                     &clos);
11526 }
11527
11528 /**
11529  * clutter_actor_unparent:
11530  * @self: a #ClutterActor
11531  *
11532  * Removes the parent of @self.
11533  *
11534  * This will cause the parent of @self to release the reference
11535  * acquired when calling clutter_actor_set_parent(), so if you
11536  * want to keep @self you will have to acquire a reference of
11537  * your own, through g_object_ref().
11538  *
11539  * This function should only be called by legacy #ClutterActor<!-- -->s
11540  * implementing the #ClutterContainer interface.
11541  *
11542  * Since: 0.1.1
11543  *
11544  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11545  */
11546 void
11547 clutter_actor_unparent (ClutterActor *self)
11548 {
11549   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11550
11551   if (self->priv->parent == NULL)
11552     return;
11553
11554   clutter_actor_remove_child_internal (self->priv->parent, self,
11555                                        REMOVE_CHILD_LEGACY_FLAGS);
11556 }
11557
11558 /**
11559  * clutter_actor_reparent:
11560  * @self: a #ClutterActor
11561  * @new_parent: the new #ClutterActor parent
11562  *
11563  * Resets the parent actor of @self.
11564  *
11565  * This function is logically equivalent to calling clutter_actor_unparent()
11566  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11567  * ensures the child is not finalized when unparented, and emits the
11568  * #ClutterActor::parent-set signal only once.
11569  *
11570  * In reality, calling this function is less useful than it sounds, as some
11571  * application code may rely on changes in the intermediate state between
11572  * removal and addition of the actor from its old parent to the @new_parent.
11573  * Thus, it is strongly encouraged to avoid using this function in application
11574  * code.
11575  *
11576  * Since: 0.2
11577  *
11578  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11579  *   clutter_actor_add_child() instead; remember to take a reference on
11580  *   the actor being removed before calling clutter_actor_remove_child()
11581  *   to avoid the reference count dropping to zero and the actor being
11582  *   destroyed.
11583  */
11584 void
11585 clutter_actor_reparent (ClutterActor *self,
11586                         ClutterActor *new_parent)
11587 {
11588   ClutterActorPrivate *priv;
11589
11590   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11591   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11592   g_return_if_fail (self != new_parent);
11593
11594   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11595     {
11596       g_warning ("Cannot set a parent on a toplevel actor");
11597       return;
11598     }
11599
11600   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11601     {
11602       g_warning ("Cannot set a parent currently being destroyed");
11603       return;
11604     }
11605
11606   priv = self->priv;
11607
11608   if (priv->parent != new_parent)
11609     {
11610       ClutterActor *old_parent;
11611
11612       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11613
11614       old_parent = priv->parent;
11615
11616       g_object_ref (self);
11617
11618       if (old_parent != NULL)
11619         {
11620          /* go through the Container implementation if this is a regular
11621           * child and not an internal one
11622           */
11623          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11624            {
11625              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11626
11627              /* this will have to call unparent() */
11628              clutter_container_remove_actor (parent, self);
11629            }
11630          else
11631            clutter_actor_remove_child_internal (old_parent, self,
11632                                                 REMOVE_CHILD_LEGACY_FLAGS);
11633         }
11634
11635       /* Note, will call set_parent() */
11636       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11637         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11638       else
11639         clutter_actor_add_child_internal (new_parent, self,
11640                                           ADD_CHILD_LEGACY_FLAGS,
11641                                           insert_child_at_depth,
11642                                           NULL);
11643
11644       /* we emit the ::parent-set signal once */
11645       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11646
11647       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11648
11649       /* the IN_REPARENT flag suspends state updates */
11650       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11651
11652       g_object_unref (self);
11653    }
11654 }
11655
11656 /**
11657  * clutter_actor_contains:
11658  * @self: A #ClutterActor
11659  * @descendant: A #ClutterActor, possibly contained in @self
11660  *
11661  * Determines if @descendant is contained inside @self (either as an
11662  * immediate child, or as a deeper descendant). If @self and
11663  * @descendant point to the same actor then it will also return %TRUE.
11664  *
11665  * Return value: whether @descendent is contained within @self
11666  *
11667  * Since: 1.4
11668  */
11669 gboolean
11670 clutter_actor_contains (ClutterActor *self,
11671                         ClutterActor *descendant)
11672 {
11673   ClutterActor *actor;
11674
11675   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11676   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11677
11678   for (actor = descendant; actor; actor = actor->priv->parent)
11679     if (actor == self)
11680       return TRUE;
11681
11682   return FALSE;
11683 }
11684
11685 /**
11686  * clutter_actor_set_child_above_sibling:
11687  * @self: a #ClutterActor
11688  * @child: a #ClutterActor child of @self
11689  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11690  *
11691  * Sets @child to be above @sibling in the list of children of @self.
11692  *
11693  * If @sibling is %NULL, @child will be the new last child of @self.
11694  *
11695  * This function is logically equivalent to removing @child and using
11696  * clutter_actor_insert_child_above(), but it will not emit signals
11697  * or change state on @child.
11698  *
11699  * Since: 1.10
11700  */
11701 void
11702 clutter_actor_set_child_above_sibling (ClutterActor *self,
11703                                        ClutterActor *child,
11704                                        ClutterActor *sibling)
11705 {
11706   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11707   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11708   g_return_if_fail (child->priv->parent == self);
11709   g_return_if_fail (child != sibling);
11710   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11711
11712   if (sibling != NULL)
11713     g_return_if_fail (sibling->priv->parent == self);
11714
11715   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11716       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11717       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11718     return;
11719
11720   /* we don't want to change the state of child, or emit signals, or
11721    * regenerate ChildMeta instances here, but we still want to follow
11722    * the correct sequence of steps encoded in remove_child() and
11723    * add_child(), so that correctness is ensured, and we only go
11724    * through one known code path.
11725    */
11726   g_object_ref (child);
11727   clutter_actor_remove_child_internal (self, child, 0);
11728   clutter_actor_add_child_internal (self, child,
11729                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11730                                     insert_child_above,
11731                                     sibling);
11732
11733   clutter_actor_queue_relayout (self);
11734 }
11735
11736 /**
11737  * clutter_actor_set_child_below_sibling:
11738  * @self: a #ClutterActor
11739  * @child: a #ClutterActor child of @self
11740  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11741  *
11742  * Sets @child to be below @sibling in the list of children of @self.
11743  *
11744  * If @sibling is %NULL, @child will be the new first child of @self.
11745  *
11746  * This function is logically equivalent to removing @self and using
11747  * clutter_actor_insert_child_below(), but it will not emit signals
11748  * or change state on @child.
11749  *
11750  * Since: 1.10
11751  */
11752 void
11753 clutter_actor_set_child_below_sibling (ClutterActor *self,
11754                                        ClutterActor *child,
11755                                        ClutterActor *sibling)
11756 {
11757   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11758   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11759   g_return_if_fail (child->priv->parent == self);
11760   g_return_if_fail (child != sibling);
11761   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11762
11763   if (sibling != NULL)
11764     g_return_if_fail (sibling->priv->parent == self);
11765
11766   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11767       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11768       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11769     return;
11770
11771   /* see the comment in set_child_above_sibling() */
11772   g_object_ref (child);
11773   clutter_actor_remove_child_internal (self, child, 0);
11774   clutter_actor_add_child_internal (self, child,
11775                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11776                                     insert_child_below,
11777                                     sibling);
11778
11779   clutter_actor_queue_relayout (self);
11780 }
11781
11782 /**
11783  * clutter_actor_set_child_at_index:
11784  * @self: a #ClutterActor
11785  * @child: a #ClutterActor child of @self
11786  * @index_: the new index for @child
11787  *
11788  * Changes the index of @child in the list of children of @self.
11789  *
11790  * This function is logically equivalent to removing @child and
11791  * calling clutter_actor_insert_child_at_index(), but it will not
11792  * emit signals or change state on @child.
11793  *
11794  * Since: 1.10
11795  */
11796 void
11797 clutter_actor_set_child_at_index (ClutterActor *self,
11798                                   ClutterActor *child,
11799                                   gint          index_)
11800 {
11801   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11802   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11803   g_return_if_fail (child->priv->parent == self);
11804   g_return_if_fail (index_ <= self->priv->n_children);
11805
11806   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11807       CLUTTER_ACTOR_IN_DESTRUCTION (child))
11808     return;
11809
11810   g_object_ref (child);
11811   clutter_actor_remove_child_internal (self, child, 0);
11812   clutter_actor_add_child_internal (self, child,
11813                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11814                                     insert_child_at_index,
11815                                     GINT_TO_POINTER (index_));
11816
11817   clutter_actor_queue_relayout (self);
11818 }
11819
11820 /**
11821  * clutter_actor_raise:
11822  * @self: A #ClutterActor
11823  * @below: (allow-none): A #ClutterActor to raise above.
11824  *
11825  * Puts @self above @below.
11826  *
11827  * Both actors must have the same parent, and the parent must implement
11828  * the #ClutterContainer interface
11829  *
11830  * This function calls clutter_container_raise_child() internally.
11831  *
11832  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11833  */
11834 void
11835 clutter_actor_raise (ClutterActor *self,
11836                      ClutterActor *below)
11837 {
11838   ClutterActor *parent;
11839
11840   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11841
11842   parent = clutter_actor_get_parent (self);
11843   if (parent == NULL)
11844     {
11845       g_warning ("%s: Actor '%s' is not inside a container",
11846                  G_STRFUNC,
11847                  _clutter_actor_get_debug_name (self));
11848       return;
11849     }
11850
11851   if (below != NULL)
11852     {
11853       if (parent != clutter_actor_get_parent (below))
11854         {
11855           g_warning ("%s Actor '%s' is not in the same container as "
11856                      "actor '%s'",
11857                      G_STRFUNC,
11858                      _clutter_actor_get_debug_name (self),
11859                      _clutter_actor_get_debug_name (below));
11860           return;
11861         }
11862     }
11863
11864   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11865 }
11866
11867 /**
11868  * clutter_actor_lower:
11869  * @self: A #ClutterActor
11870  * @above: (allow-none): A #ClutterActor to lower below
11871  *
11872  * Puts @self below @above.
11873  *
11874  * Both actors must have the same parent, and the parent must implement
11875  * the #ClutterContainer interface.
11876  *
11877  * This function calls clutter_container_lower_child() internally.
11878  *
11879  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11880  */
11881 void
11882 clutter_actor_lower (ClutterActor *self,
11883                      ClutterActor *above)
11884 {
11885   ClutterActor *parent;
11886
11887   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11888
11889   parent = clutter_actor_get_parent (self);
11890   if (parent == NULL)
11891     {
11892       g_warning ("%s: Actor of type %s is not inside a container",
11893                  G_STRFUNC,
11894                  _clutter_actor_get_debug_name (self));
11895       return;
11896     }
11897
11898   if (above)
11899     {
11900       if (parent != clutter_actor_get_parent (above))
11901         {
11902           g_warning ("%s: Actor '%s' is not in the same container as "
11903                      "actor '%s'",
11904                      G_STRFUNC,
11905                      _clutter_actor_get_debug_name (self),
11906                      _clutter_actor_get_debug_name (above));
11907           return;
11908         }
11909     }
11910
11911   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11912 }
11913
11914 /**
11915  * clutter_actor_raise_top:
11916  * @self: A #ClutterActor
11917  *
11918  * Raises @self to the top.
11919  *
11920  * This function calls clutter_actor_raise() internally.
11921  *
11922  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11923  *   a %NULL sibling, instead.
11924  */
11925 void
11926 clutter_actor_raise_top (ClutterActor *self)
11927 {
11928   clutter_actor_raise (self, NULL);
11929 }
11930
11931 /**
11932  * clutter_actor_lower_bottom:
11933  * @self: A #ClutterActor
11934  *
11935  * Lowers @self to the bottom.
11936  *
11937  * This function calls clutter_actor_lower() internally.
11938  *
11939  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11940  *   a %NULL sibling, instead.
11941  */
11942 void
11943 clutter_actor_lower_bottom (ClutterActor *self)
11944 {
11945   clutter_actor_lower (self, NULL);
11946 }
11947
11948 /*
11949  * Event handling
11950  */
11951
11952 /**
11953  * clutter_actor_event:
11954  * @actor: a #ClutterActor
11955  * @event: a #ClutterEvent
11956  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11957  *
11958  * This function is used to emit an event on the main stage.
11959  * You should rarely need to use this function, except for
11960  * synthetising events.
11961  *
11962  * Return value: the return value from the signal emission: %TRUE
11963  *   if the actor handled the event, or %FALSE if the event was
11964  *   not handled
11965  *
11966  * Since: 0.6
11967  */
11968 gboolean
11969 clutter_actor_event (ClutterActor *actor,
11970                      ClutterEvent *event,
11971                      gboolean      capture)
11972 {
11973   gboolean retval = FALSE;
11974   gint signal_num = -1;
11975
11976   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11977   g_return_val_if_fail (event != NULL, FALSE);
11978
11979   g_object_ref (actor);
11980
11981   if (capture)
11982     {
11983       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11984                      event,
11985                      &retval);
11986       goto out;
11987     }
11988
11989   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11990
11991   if (!retval)
11992     {
11993       switch (event->type)
11994         {
11995         case CLUTTER_NOTHING:
11996           break;
11997         case CLUTTER_BUTTON_PRESS:
11998           signal_num = BUTTON_PRESS_EVENT;
11999           break;
12000         case CLUTTER_BUTTON_RELEASE:
12001           signal_num = BUTTON_RELEASE_EVENT;
12002           break;
12003         case CLUTTER_SCROLL:
12004           signal_num = SCROLL_EVENT;
12005           break;
12006         case CLUTTER_KEY_PRESS:
12007           signal_num = KEY_PRESS_EVENT;
12008           break;
12009         case CLUTTER_KEY_RELEASE:
12010           signal_num = KEY_RELEASE_EVENT;
12011           break;
12012         case CLUTTER_MOTION:
12013           signal_num = MOTION_EVENT;
12014           break;
12015         case CLUTTER_ENTER:
12016           signal_num = ENTER_EVENT;
12017           break;
12018         case CLUTTER_LEAVE:
12019           signal_num = LEAVE_EVENT;
12020           break;
12021         case CLUTTER_DELETE:
12022         case CLUTTER_DESTROY_NOTIFY:
12023         case CLUTTER_CLIENT_MESSAGE:
12024         default:
12025           signal_num = -1;
12026           break;
12027         }
12028
12029       if (signal_num != -1)
12030         g_signal_emit (actor, actor_signals[signal_num], 0,
12031                        event, &retval);
12032     }
12033
12034 out:
12035   g_object_unref (actor);
12036
12037   return retval;
12038 }
12039
12040 /**
12041  * clutter_actor_set_reactive:
12042  * @actor: a #ClutterActor
12043  * @reactive: whether the actor should be reactive to events
12044  *
12045  * Sets @actor as reactive. Reactive actors will receive events.
12046  *
12047  * Since: 0.6
12048  */
12049 void
12050 clutter_actor_set_reactive (ClutterActor *actor,
12051                             gboolean      reactive)
12052 {
12053   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12054
12055   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12056     return;
12057
12058   if (reactive)
12059     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12060   else
12061     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12062
12063   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12064 }
12065
12066 /**
12067  * clutter_actor_get_reactive:
12068  * @actor: a #ClutterActor
12069  *
12070  * Checks whether @actor is marked as reactive.
12071  *
12072  * Return value: %TRUE if the actor is reactive
12073  *
12074  * Since: 0.6
12075  */
12076 gboolean
12077 clutter_actor_get_reactive (ClutterActor *actor)
12078 {
12079   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12080
12081   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12082 }
12083
12084 /**
12085  * clutter_actor_get_anchor_point:
12086  * @self: a #ClutterActor
12087  * @anchor_x: (out): return location for the X coordinate of the anchor point
12088  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12089  *
12090  * Gets the current anchor point of the @actor in pixels.
12091  *
12092  * Since: 0.6
12093  */
12094 void
12095 clutter_actor_get_anchor_point (ClutterActor *self,
12096                                 gfloat       *anchor_x,
12097                                 gfloat       *anchor_y)
12098 {
12099   const ClutterTransformInfo *info;
12100
12101   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12102
12103   info = _clutter_actor_get_transform_info_or_defaults (self);
12104   clutter_anchor_coord_get_units (self, &info->anchor,
12105                                   anchor_x,
12106                                   anchor_y,
12107                                   NULL);
12108 }
12109
12110 /**
12111  * clutter_actor_set_anchor_point:
12112  * @self: a #ClutterActor
12113  * @anchor_x: X coordinate of the anchor point
12114  * @anchor_y: Y coordinate of the anchor point
12115  *
12116  * Sets an anchor point for @self. The anchor point is a point in the
12117  * coordinate space of an actor to which the actor position within its
12118  * parent is relative; the default is (0, 0), i.e. the top-left corner
12119  * of the actor.
12120  *
12121  * Since: 0.6
12122  */
12123 void
12124 clutter_actor_set_anchor_point (ClutterActor *self,
12125                                 gfloat        anchor_x,
12126                                 gfloat        anchor_y)
12127 {
12128   ClutterTransformInfo *info;
12129   ClutterActorPrivate *priv;
12130   gboolean changed = FALSE;
12131   gfloat old_anchor_x, old_anchor_y;
12132   GObject *obj;
12133
12134   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12135
12136   obj = G_OBJECT (self);
12137   priv = self->priv;
12138   info = _clutter_actor_get_transform_info (self);
12139
12140   g_object_freeze_notify (obj);
12141
12142   clutter_anchor_coord_get_units (self, &info->anchor,
12143                                   &old_anchor_x,
12144                                   &old_anchor_y,
12145                                   NULL);
12146
12147   if (info->anchor.is_fractional)
12148     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12149
12150   if (old_anchor_x != anchor_x)
12151     {
12152       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12153       changed = TRUE;
12154     }
12155
12156   if (old_anchor_y != anchor_y)
12157     {
12158       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12159       changed = TRUE;
12160     }
12161
12162   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12163
12164   if (changed)
12165     {
12166       priv->transform_valid = FALSE;
12167       clutter_actor_queue_redraw (self);
12168     }
12169
12170   g_object_thaw_notify (obj);
12171 }
12172
12173 /**
12174  * clutter_actor_get_anchor_point_gravity:
12175  * @self: a #ClutterActor
12176  *
12177  * Retrieves the anchor position expressed as a #ClutterGravity. If
12178  * the anchor point was specified using pixels or units this will
12179  * return %CLUTTER_GRAVITY_NONE.
12180  *
12181  * Return value: the #ClutterGravity used by the anchor point
12182  *
12183  * Since: 1.0
12184  */
12185 ClutterGravity
12186 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12187 {
12188   const ClutterTransformInfo *info;
12189
12190   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12191
12192   info = _clutter_actor_get_transform_info_or_defaults (self);
12193
12194   return clutter_anchor_coord_get_gravity (&info->anchor);
12195 }
12196
12197 /**
12198  * clutter_actor_move_anchor_point:
12199  * @self: a #ClutterActor
12200  * @anchor_x: X coordinate of the anchor point
12201  * @anchor_y: Y coordinate of the anchor point
12202  *
12203  * Sets an anchor point for the actor, and adjusts the actor postion so that
12204  * the relative position of the actor toward its parent remains the same.
12205  *
12206  * Since: 0.6
12207  */
12208 void
12209 clutter_actor_move_anchor_point (ClutterActor *self,
12210                                  gfloat        anchor_x,
12211                                  gfloat        anchor_y)
12212 {
12213   gfloat old_anchor_x, old_anchor_y;
12214   const ClutterTransformInfo *info;
12215
12216   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12217
12218   info = _clutter_actor_get_transform_info (self);
12219   clutter_anchor_coord_get_units (self, &info->anchor,
12220                                   &old_anchor_x,
12221                                   &old_anchor_y,
12222                                   NULL);
12223
12224   g_object_freeze_notify (G_OBJECT (self));
12225
12226   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12227
12228   if (self->priv->position_set)
12229     clutter_actor_move_by (self,
12230                            anchor_x - old_anchor_x,
12231                            anchor_y - old_anchor_y);
12232
12233   g_object_thaw_notify (G_OBJECT (self));
12234 }
12235
12236 /**
12237  * clutter_actor_move_anchor_point_from_gravity:
12238  * @self: a #ClutterActor
12239  * @gravity: #ClutterGravity.
12240  *
12241  * Sets an anchor point on the actor based on the given gravity, adjusting the
12242  * actor postion so that its relative position within its parent remains
12243  * unchanged.
12244  *
12245  * Since version 1.0 the anchor point will be stored as a gravity so
12246  * that if the actor changes size then the anchor point will move. For
12247  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12248  * and later double the size of the actor, the anchor point will move
12249  * to the bottom right.
12250  *
12251  * Since: 0.6
12252  */
12253 void
12254 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12255                                               ClutterGravity  gravity)
12256 {
12257   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12258   const ClutterTransformInfo *info;
12259   ClutterActorPrivate *priv;
12260
12261   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12262
12263   priv = self->priv;
12264   info = _clutter_actor_get_transform_info (self);
12265
12266   g_object_freeze_notify (G_OBJECT (self));
12267
12268   clutter_anchor_coord_get_units (self, &info->anchor,
12269                                   &old_anchor_x,
12270                                   &old_anchor_y,
12271                                   NULL);
12272   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12273   clutter_anchor_coord_get_units (self, &info->anchor,
12274                                   &new_anchor_x,
12275                                   &new_anchor_y,
12276                                   NULL);
12277
12278   if (priv->position_set)
12279     clutter_actor_move_by (self,
12280                            new_anchor_x - old_anchor_x,
12281                            new_anchor_y - old_anchor_y);
12282
12283   g_object_thaw_notify (G_OBJECT (self));
12284 }
12285
12286 /**
12287  * clutter_actor_set_anchor_point_from_gravity:
12288  * @self: a #ClutterActor
12289  * @gravity: #ClutterGravity.
12290  *
12291  * Sets an anchor point on the actor, based on the given gravity (this is a
12292  * convenience function wrapping clutter_actor_set_anchor_point()).
12293  *
12294  * Since version 1.0 the anchor point will be stored as a gravity so
12295  * that if the actor changes size then the anchor point will move. For
12296  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12297  * and later double the size of the actor, the anchor point will move
12298  * to the bottom right.
12299  *
12300  * Since: 0.6
12301  */
12302 void
12303 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12304                                              ClutterGravity  gravity)
12305 {
12306   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12307
12308   if (gravity == CLUTTER_GRAVITY_NONE)
12309     clutter_actor_set_anchor_point (self, 0, 0);
12310   else
12311     {
12312       GObject *obj = G_OBJECT (self);
12313       ClutterTransformInfo *info;
12314
12315       g_object_freeze_notify (obj);
12316
12317       info = _clutter_actor_get_transform_info (self);
12318       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12319
12320       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12321       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12322       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12323
12324       self->priv->transform_valid = FALSE;
12325
12326       clutter_actor_queue_redraw (self);
12327
12328       g_object_thaw_notify (obj);
12329     }
12330 }
12331
12332 static void
12333 clutter_actor_store_content_box (ClutterActor *self,
12334                                  const ClutterActorBox *box)
12335 {
12336   if (box != NULL)
12337     {
12338       self->priv->content_box = *box;
12339       self->priv->content_box_valid = TRUE;
12340     }
12341   else
12342     self->priv->content_box_valid = FALSE;
12343
12344   clutter_actor_queue_redraw (self);
12345
12346   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12347 }
12348
12349 static void
12350 clutter_container_iface_init (ClutterContainerIface *iface)
12351 {
12352   /* we don't override anything, as ClutterContainer already has a default
12353    * implementation that we can use, and which calls into our own API.
12354    */
12355 }
12356
12357 typedef enum
12358 {
12359   PARSE_X,
12360   PARSE_Y,
12361   PARSE_WIDTH,
12362   PARSE_HEIGHT,
12363   PARSE_ANCHOR_X,
12364   PARSE_ANCHOR_Y
12365 } ParseDimension;
12366
12367 static gfloat
12368 parse_units (ClutterActor   *self,
12369              ParseDimension  dimension,
12370              JsonNode       *node)
12371 {
12372   GValue value = G_VALUE_INIT;
12373   gfloat retval = 0;
12374
12375   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12376     return 0;
12377
12378   json_node_get_value (node, &value);
12379
12380   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12381     {
12382       retval = (gfloat) g_value_get_int64 (&value);
12383     }
12384   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12385     {
12386       retval = g_value_get_double (&value);
12387     }
12388   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12389     {
12390       ClutterUnits units;
12391       gboolean res;
12392
12393       res = clutter_units_from_string (&units, g_value_get_string (&value));
12394       if (res)
12395         retval = clutter_units_to_pixels (&units);
12396       else
12397         {
12398           g_warning ("Invalid value '%s': integers, strings or floating point "
12399                      "values can be used for the x, y, width and height "
12400                      "properties. Valid modifiers for strings are 'px', 'mm', "
12401                      "'pt' and 'em'.",
12402                      g_value_get_string (&value));
12403           retval = 0;
12404         }
12405     }
12406   else
12407     {
12408       g_warning ("Invalid value of type '%s': integers, strings of floating "
12409                  "point values can be used for the x, y, width, height "
12410                  "anchor-x and anchor-y properties.",
12411                  g_type_name (G_VALUE_TYPE (&value)));
12412     }
12413
12414   g_value_unset (&value);
12415
12416   return retval;
12417 }
12418
12419 typedef struct {
12420   ClutterRotateAxis axis;
12421
12422   gdouble angle;
12423
12424   gfloat center_x;
12425   gfloat center_y;
12426   gfloat center_z;
12427 } RotationInfo;
12428
12429 static inline gboolean
12430 parse_rotation_array (ClutterActor *actor,
12431                       JsonArray    *array,
12432                       RotationInfo *info)
12433 {
12434   JsonNode *element;
12435
12436   if (json_array_get_length (array) != 2)
12437     return FALSE;
12438
12439   /* angle */
12440   element = json_array_get_element (array, 0);
12441   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12442     info->angle = json_node_get_double (element);
12443   else
12444     return FALSE;
12445
12446   /* center */
12447   element = json_array_get_element (array, 1);
12448   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12449     {
12450       JsonArray *center = json_node_get_array (element);
12451
12452       if (json_array_get_length (center) != 2)
12453         return FALSE;
12454
12455       switch (info->axis)
12456         {
12457         case CLUTTER_X_AXIS:
12458           info->center_y = parse_units (actor, PARSE_Y,
12459                                         json_array_get_element (center, 0));
12460           info->center_z = parse_units (actor, PARSE_Y,
12461                                         json_array_get_element (center, 1));
12462           return TRUE;
12463
12464         case CLUTTER_Y_AXIS:
12465           info->center_x = parse_units (actor, PARSE_X,
12466                                         json_array_get_element (center, 0));
12467           info->center_z = parse_units (actor, PARSE_X,
12468                                         json_array_get_element (center, 1));
12469           return TRUE;
12470
12471         case CLUTTER_Z_AXIS:
12472           info->center_x = parse_units (actor, PARSE_X,
12473                                         json_array_get_element (center, 0));
12474           info->center_y = parse_units (actor, PARSE_Y,
12475                                         json_array_get_element (center, 1));
12476           return TRUE;
12477         }
12478     }
12479
12480   return FALSE;
12481 }
12482
12483 static gboolean
12484 parse_rotation (ClutterActor *actor,
12485                 JsonNode     *node,
12486                 RotationInfo *info)
12487 {
12488   JsonArray *array;
12489   guint len, i;
12490   gboolean retval = FALSE;
12491
12492   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12493     {
12494       g_warning ("Invalid node of type '%s' found, expecting an array",
12495                  json_node_type_name (node));
12496       return FALSE;
12497     }
12498
12499   array = json_node_get_array (node);
12500   len = json_array_get_length (array);
12501
12502   for (i = 0; i < len; i++)
12503     {
12504       JsonNode *element = json_array_get_element (array, i);
12505       JsonObject *object;
12506       JsonNode *member;
12507
12508       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12509         {
12510           g_warning ("Invalid node of type '%s' found, expecting an object",
12511                      json_node_type_name (element));
12512           return FALSE;
12513         }
12514
12515       object = json_node_get_object (element);
12516
12517       if (json_object_has_member (object, "x-axis"))
12518         {
12519           member = json_object_get_member (object, "x-axis");
12520
12521           info->axis = CLUTTER_X_AXIS;
12522
12523           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12524             {
12525               info->angle = json_node_get_double (member);
12526               retval = TRUE;
12527             }
12528           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12529             retval = parse_rotation_array (actor,
12530                                            json_node_get_array (member),
12531                                            info);
12532           else
12533             retval = FALSE;
12534         }
12535       else if (json_object_has_member (object, "y-axis"))
12536         {
12537           member = json_object_get_member (object, "y-axis");
12538
12539           info->axis = CLUTTER_Y_AXIS;
12540
12541           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12542             {
12543               info->angle = json_node_get_double (member);
12544               retval = TRUE;
12545             }
12546           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12547             retval = parse_rotation_array (actor,
12548                                            json_node_get_array (member),
12549                                            info);
12550           else
12551             retval = FALSE;
12552         }
12553       else if (json_object_has_member (object, "z-axis"))
12554         {
12555           member = json_object_get_member (object, "z-axis");
12556
12557           info->axis = CLUTTER_Z_AXIS;
12558
12559           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12560             {
12561               info->angle = json_node_get_double (member);
12562               retval = TRUE;
12563             }
12564           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12565             retval = parse_rotation_array (actor,
12566                                            json_node_get_array (member),
12567                                            info);
12568           else
12569             retval = FALSE;
12570         }
12571     }
12572
12573   return retval;
12574 }
12575
12576 static GSList *
12577 parse_actor_metas (ClutterScript *script,
12578                    ClutterActor  *actor,
12579                    JsonNode      *node)
12580 {
12581   GList *elements, *l;
12582   GSList *retval = NULL;
12583
12584   if (!JSON_NODE_HOLDS_ARRAY (node))
12585     return NULL;
12586
12587   elements = json_array_get_elements (json_node_get_array (node));
12588
12589   for (l = elements; l != NULL; l = l->next)
12590     {
12591       JsonNode *element = l->data;
12592       const gchar *id_ = _clutter_script_get_id_from_node (element);
12593       GObject *meta;
12594
12595       if (id_ == NULL || *id_ == '\0')
12596         continue;
12597
12598       meta = clutter_script_get_object (script, id_);
12599       if (meta == NULL)
12600         continue;
12601
12602       retval = g_slist_prepend (retval, meta);
12603     }
12604
12605   g_list_free (elements);
12606
12607   return g_slist_reverse (retval);
12608 }
12609
12610 static GSList *
12611 parse_behaviours (ClutterScript *script,
12612                   ClutterActor  *actor,
12613                   JsonNode      *node)
12614 {
12615   GList *elements, *l;
12616   GSList *retval = NULL;
12617
12618   if (!JSON_NODE_HOLDS_ARRAY (node))
12619     return NULL;
12620
12621   elements = json_array_get_elements (json_node_get_array (node));
12622
12623   for (l = elements; l != NULL; l = l->next)
12624     {
12625       JsonNode *element = l->data;
12626       const gchar *id_ = _clutter_script_get_id_from_node (element);
12627       GObject *behaviour;
12628
12629       if (id_ == NULL || *id_ == '\0')
12630         continue;
12631
12632       behaviour = clutter_script_get_object (script, id_);
12633       if (behaviour == NULL)
12634         continue;
12635
12636       retval = g_slist_prepend (retval, behaviour);
12637     }
12638
12639   g_list_free (elements);
12640
12641   return g_slist_reverse (retval);
12642 }
12643
12644 static gboolean
12645 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12646                                  ClutterScript     *script,
12647                                  GValue            *value,
12648                                  const gchar       *name,
12649                                  JsonNode          *node)
12650 {
12651   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12652   gboolean retval = FALSE;
12653
12654   if ((name[0] == 'x' && name[1] == '\0') ||
12655       (name[0] == 'y' && name[1] == '\0') ||
12656       (strcmp (name, "width") == 0) ||
12657       (strcmp (name, "height") == 0) ||
12658       (strcmp (name, "anchor_x") == 0) ||
12659       (strcmp (name, "anchor_y") == 0))
12660     {
12661       ParseDimension dimension;
12662       gfloat units;
12663
12664       if (name[0] == 'x')
12665         dimension = PARSE_X;
12666       else if (name[0] == 'y')
12667         dimension = PARSE_Y;
12668       else if (name[0] == 'w')
12669         dimension = PARSE_WIDTH;
12670       else if (name[0] == 'h')
12671         dimension = PARSE_HEIGHT;
12672       else if (name[0] == 'a' && name[7] == 'x')
12673         dimension = PARSE_ANCHOR_X;
12674       else if (name[0] == 'a' && name[7] == 'y')
12675         dimension = PARSE_ANCHOR_Y;
12676       else
12677         return FALSE;
12678
12679       units = parse_units (actor, dimension, node);
12680
12681       /* convert back to pixels: all properties are pixel-based */
12682       g_value_init (value, G_TYPE_FLOAT);
12683       g_value_set_float (value, units);
12684
12685       retval = TRUE;
12686     }
12687   else if (strcmp (name, "rotation") == 0)
12688     {
12689       RotationInfo *info;
12690
12691       info = g_slice_new0 (RotationInfo);
12692       retval = parse_rotation (actor, node, info);
12693
12694       if (retval)
12695         {
12696           g_value_init (value, G_TYPE_POINTER);
12697           g_value_set_pointer (value, info);
12698         }
12699       else
12700         g_slice_free (RotationInfo, info);
12701     }
12702   else if (strcmp (name, "behaviours") == 0)
12703     {
12704       GSList *l;
12705
12706 #ifdef CLUTTER_ENABLE_DEBUG
12707       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12708         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12709                                      "and it should not be used in newly "
12710                                      "written ClutterScript definitions.");
12711 #endif
12712
12713       l = parse_behaviours (script, actor, node);
12714
12715       g_value_init (value, G_TYPE_POINTER);
12716       g_value_set_pointer (value, l);
12717
12718       retval = TRUE;
12719     }
12720   else if (strcmp (name, "actions") == 0 ||
12721            strcmp (name, "constraints") == 0 ||
12722            strcmp (name, "effects") == 0)
12723     {
12724       GSList *l;
12725
12726       l = parse_actor_metas (script, actor, node);
12727
12728       g_value_init (value, G_TYPE_POINTER);
12729       g_value_set_pointer (value, l);
12730
12731       retval = TRUE;
12732     }
12733
12734   return retval;
12735 }
12736
12737 static void
12738 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12739                                    ClutterScript     *script,
12740                                    const gchar       *name,
12741                                    const GValue      *value)
12742 {
12743   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12744
12745 #ifdef CLUTTER_ENABLE_DEBUG
12746   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12747     {
12748       gchar *tmp = g_strdup_value_contents (value);
12749
12750       CLUTTER_NOTE (SCRIPT,
12751                     "in ClutterActor::set_custom_property('%s') = %s",
12752                     name,
12753                     tmp);
12754
12755       g_free (tmp);
12756     }
12757 #endif /* CLUTTER_ENABLE_DEBUG */
12758
12759   if (strcmp (name, "rotation") == 0)
12760     {
12761       RotationInfo *info;
12762
12763       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12764         return;
12765
12766       info = g_value_get_pointer (value);
12767
12768       clutter_actor_set_rotation (actor,
12769                                   info->axis, info->angle,
12770                                   info->center_x,
12771                                   info->center_y,
12772                                   info->center_z);
12773
12774       g_slice_free (RotationInfo, info);
12775
12776       return;
12777     }
12778
12779   if (strcmp (name, "behaviours") == 0)
12780     {
12781       GSList *behaviours, *l;
12782
12783       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12784         return;
12785
12786       behaviours = g_value_get_pointer (value);
12787       for (l = behaviours; l != NULL; l = l->next)
12788         {
12789           ClutterBehaviour *behaviour = l->data;
12790
12791           clutter_behaviour_apply (behaviour, actor);
12792         }
12793
12794       g_slist_free (behaviours);
12795
12796       return;
12797     }
12798
12799   if (strcmp (name, "actions") == 0 ||
12800       strcmp (name, "constraints") == 0 ||
12801       strcmp (name, "effects") == 0)
12802     {
12803       GSList *metas, *l;
12804
12805       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12806         return;
12807
12808       metas = g_value_get_pointer (value);
12809       for (l = metas; l != NULL; l = l->next)
12810         {
12811           if (name[0] == 'a')
12812             clutter_actor_add_action (actor, l->data);
12813
12814           if (name[0] == 'c')
12815             clutter_actor_add_constraint (actor, l->data);
12816
12817           if (name[0] == 'e')
12818             clutter_actor_add_effect (actor, l->data);
12819         }
12820
12821       g_slist_free (metas);
12822
12823       return;
12824     }
12825
12826   g_object_set_property (G_OBJECT (scriptable), name, value);
12827 }
12828
12829 static void
12830 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12831 {
12832   iface->parse_custom_node = clutter_actor_parse_custom_node;
12833   iface->set_custom_property = clutter_actor_set_custom_property;
12834 }
12835
12836 static ClutterActorMeta *
12837 get_meta_from_animation_property (ClutterActor  *actor,
12838                                   const gchar   *name,
12839                                   gchar        **name_p)
12840 {
12841   ClutterActorPrivate *priv = actor->priv;
12842   ClutterActorMeta *meta = NULL;
12843   gchar **tokens;
12844
12845   /* if this is not a special property, fall through */
12846   if (name[0] != '@')
12847     return NULL;
12848
12849   /* detect the properties named using the following spec:
12850    *
12851    *   @<section>.<meta-name>.<property-name>
12852    *
12853    * where <section> can be one of the following:
12854    *
12855    *   - actions
12856    *   - constraints
12857    *   - effects
12858    *
12859    * and <meta-name> is the name set on a specific ActorMeta
12860    */
12861
12862   tokens = g_strsplit (name + 1, ".", -1);
12863   if (tokens == NULL || g_strv_length (tokens) != 3)
12864     {
12865       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12866                     name + 1);
12867       g_strfreev (tokens);
12868       return NULL;
12869     }
12870
12871   if (strcmp (tokens[0], "actions") == 0)
12872     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12873
12874   if (strcmp (tokens[0], "constraints") == 0)
12875     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12876
12877   if (strcmp (tokens[0], "effects") == 0)
12878     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12879
12880   if (name_p != NULL)
12881     *name_p = g_strdup (tokens[2]);
12882
12883   CLUTTER_NOTE (ANIMATION,
12884                 "Looking for property '%s' of object '%s' in section '%s'",
12885                 tokens[2],
12886                 tokens[1],
12887                 tokens[0]);
12888
12889   g_strfreev (tokens);
12890
12891   return meta;
12892 }
12893
12894 static GParamSpec *
12895 clutter_actor_find_property (ClutterAnimatable *animatable,
12896                              const gchar       *property_name)
12897 {
12898   ClutterActorMeta *meta = NULL;
12899   GObjectClass *klass = NULL;
12900   GParamSpec *pspec = NULL;
12901   gchar *p_name = NULL;
12902
12903   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12904                                            property_name,
12905                                            &p_name);
12906
12907   if (meta != NULL)
12908     {
12909       klass = G_OBJECT_GET_CLASS (meta);
12910
12911       pspec = g_object_class_find_property (klass, p_name);
12912     }
12913   else
12914     {
12915       klass = G_OBJECT_GET_CLASS (animatable);
12916
12917       pspec = g_object_class_find_property (klass, property_name);
12918     }
12919
12920   g_free (p_name);
12921
12922   return pspec;
12923 }
12924
12925 static void
12926 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12927                                  const gchar       *property_name,
12928                                  GValue            *initial)
12929 {
12930   ClutterActorMeta *meta = NULL;
12931   gchar *p_name = NULL;
12932
12933   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12934                                            property_name,
12935                                            &p_name);
12936
12937   if (meta != NULL)
12938     g_object_get_property (G_OBJECT (meta), p_name, initial);
12939   else
12940     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12941
12942   g_free (p_name);
12943 }
12944
12945 /*
12946  * clutter_actor_set_animatable_property:
12947  * @actor: a #ClutterActor
12948  * @prop_id: the paramspec id
12949  * @value: the value to set
12950  * @pspec: the paramspec
12951  *
12952  * Sets values of animatable properties.
12953  *
12954  * This is a variant of clutter_actor_set_property() that gets called
12955  * by the #ClutterAnimatable implementation of #ClutterActor for the
12956  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12957  * #GParamSpec.
12958  *
12959  * Unlike the implementation of #GObjectClass.set_property(), this
12960  * function will not update the interval if a transition involving an
12961  * animatable property is in progress - this avoids cycles with the
12962  * transition API calling the public API.
12963  */
12964 static void
12965 clutter_actor_set_animatable_property (ClutterActor *actor,
12966                                        guint         prop_id,
12967                                        const GValue *value,
12968                                        GParamSpec   *pspec)
12969 {
12970   GObject *obj = G_OBJECT (actor);
12971
12972   g_object_freeze_notify (obj);
12973
12974   switch (prop_id)
12975     {
12976     case PROP_X:
12977       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12978       break;
12979
12980     case PROP_Y:
12981       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12982       break;
12983
12984     case PROP_WIDTH:
12985       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12986       break;
12987
12988     case PROP_HEIGHT:
12989       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12990       break;
12991
12992     case PROP_DEPTH:
12993       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12994       break;
12995
12996     case PROP_OPACITY:
12997       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12998       break;
12999
13000     case PROP_BACKGROUND_COLOR:
13001       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
13002       break;
13003
13004     case PROP_SCALE_X:
13005       clutter_actor_set_scale_factor_internal (actor,
13006                                                g_value_get_double (value),
13007                                                pspec);
13008       break;
13009
13010     case PROP_SCALE_Y:
13011       clutter_actor_set_scale_factor_internal (actor,
13012                                                g_value_get_double (value),
13013                                                pspec);
13014       break;
13015
13016     case PROP_ROTATION_ANGLE_X:
13017       clutter_actor_set_rotation_angle_internal (actor,
13018                                                  CLUTTER_X_AXIS,
13019                                                  g_value_get_double (value));
13020       break;
13021
13022     case PROP_ROTATION_ANGLE_Y:
13023       clutter_actor_set_rotation_angle_internal (actor,
13024                                                  CLUTTER_Y_AXIS,
13025                                                  g_value_get_double (value));
13026       break;
13027
13028     case PROP_ROTATION_ANGLE_Z:
13029       clutter_actor_set_rotation_angle_internal (actor,
13030                                                  CLUTTER_Z_AXIS,
13031                                                  g_value_get_double (value));
13032       break;
13033
13034     case PROP_CONTENT_BOX:
13035       clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13036       break;
13037
13038     default:
13039       g_object_set_property (obj, pspec->name, value);
13040       break;
13041     }
13042
13043   g_object_thaw_notify (obj);
13044 }
13045
13046 static void
13047 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13048                                const gchar       *property_name,
13049                                const GValue      *final)
13050 {
13051   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13052   ClutterActorMeta *meta = NULL;
13053   gchar *p_name = NULL;
13054
13055   meta = get_meta_from_animation_property (actor,
13056                                            property_name,
13057                                            &p_name);
13058   if (meta != NULL)
13059     g_object_set_property (G_OBJECT (meta), p_name, final);
13060   else
13061     {
13062       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13063       GParamSpec *pspec;
13064
13065       pspec = g_object_class_find_property (obj_class, property_name);
13066
13067       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13068         {
13069           /* XXX - I'm going to the special hell for this */
13070           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13071         }
13072       else
13073         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13074     }
13075
13076   g_free (p_name);
13077 }
13078
13079 static void
13080 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13081 {
13082   iface->find_property = clutter_actor_find_property;
13083   iface->get_initial_state = clutter_actor_get_initial_state;
13084   iface->set_final_state = clutter_actor_set_final_state;
13085 }
13086
13087 /**
13088  * clutter_actor_transform_stage_point:
13089  * @self: A #ClutterActor
13090  * @x: (in): x screen coordinate of the point to unproject
13091  * @y: (in): y screen coordinate of the point to unproject
13092  * @x_out: (out): return location for the unprojected x coordinance
13093  * @y_out: (out): return location for the unprojected y coordinance
13094  *
13095  * This function translates screen coordinates (@x, @y) to
13096  * coordinates relative to the actor. For example, it can be used to translate
13097  * screen events from global screen coordinates into actor-local coordinates.
13098  *
13099  * The conversion can fail, notably if the transform stack results in the
13100  * actor being projected on the screen as a mere line.
13101  *
13102  * The conversion should not be expected to be pixel-perfect due to the
13103  * nature of the operation. In general the error grows when the skewing
13104  * of the actor rectangle on screen increases.
13105  *
13106  * <note><para>This function can be computationally intensive.</para></note>
13107  *
13108  * <note><para>This function only works when the allocation is up-to-date,
13109  * i.e. inside of paint().</para></note>
13110  *
13111  * Return value: %TRUE if conversion was successful.
13112  *
13113  * Since: 0.6
13114  */
13115 gboolean
13116 clutter_actor_transform_stage_point (ClutterActor *self,
13117                                      gfloat        x,
13118                                      gfloat        y,
13119                                      gfloat       *x_out,
13120                                      gfloat       *y_out)
13121 {
13122   ClutterVertex v[4];
13123   float ST[3][3];
13124   float RQ[3][3];
13125   int du, dv, xi, yi;
13126   float px, py;
13127   float xf, yf, wf, det;
13128   ClutterActorPrivate *priv;
13129
13130   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13131
13132   priv = self->priv;
13133
13134   /* This implementation is based on the quad -> quad projection algorithm
13135    * described by Paul Heckbert in:
13136    *
13137    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13138    *
13139    * and the sample implementation at:
13140    *
13141    *   http://www.cs.cmu.edu/~ph/src/texfund/
13142    *
13143    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13144    * quad to rectangle only, which significantly simplifies things; the
13145    * function calls have been unrolled, and most of the math is done in fixed
13146    * point.
13147    */
13148
13149   clutter_actor_get_abs_allocation_vertices (self, v);
13150
13151   /* Keeping these as ints simplifies the multiplication (no significant
13152    * loss of precision here).
13153    */
13154   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13155   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13156
13157   if (!du || !dv)
13158     return FALSE;
13159
13160 #define UX2FP(x)        (x)
13161 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13162
13163   /* First, find mapping from unit uv square to xy quadrilateral; this
13164    * equivalent to the pmap_square_quad() functions in the sample
13165    * implementation, which we can simplify, since our target is always
13166    * a rectangle.
13167    */
13168   px = v[0].x - v[1].x + v[3].x - v[2].x;
13169   py = v[0].y - v[1].y + v[3].y - v[2].y;
13170
13171   if (!px && !py)
13172     {
13173       /* affine transform */
13174       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13175       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13176       RQ[2][0] = UX2FP (v[0].x);
13177       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13178       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13179       RQ[2][1] = UX2FP (v[0].y);
13180       RQ[0][2] = 0;
13181       RQ[1][2] = 0;
13182       RQ[2][2] = 1.0;
13183     }
13184   else
13185     {
13186       /* projective transform */
13187       double dx1, dx2, dy1, dy2, del;
13188
13189       dx1 = UX2FP (v[1].x - v[3].x);
13190       dx2 = UX2FP (v[2].x - v[3].x);
13191       dy1 = UX2FP (v[1].y - v[3].y);
13192       dy2 = UX2FP (v[2].y - v[3].y);
13193
13194       del = DET2FP (dx1, dx2, dy1, dy2);
13195       if (!del)
13196         return FALSE;
13197
13198       /*
13199        * The division here needs to be done in floating point for
13200        * precisions reasons.
13201        */
13202       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13203       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13204       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13205       RQ[2][2] = 1.0;
13206       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13207       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13208       RQ[2][0] = UX2FP (v[0].x);
13209       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13210       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13211       RQ[2][1] = UX2FP (v[0].y);
13212     }
13213
13214   /*
13215    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13216    * square. Since our rectangle is based at 0,0 we only need to scale.
13217    */
13218   RQ[0][0] /= du;
13219   RQ[1][0] /= dv;
13220   RQ[0][1] /= du;
13221   RQ[1][1] /= dv;
13222   RQ[0][2] /= du;
13223   RQ[1][2] /= dv;
13224
13225   /*
13226    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13227    * inverse of that.
13228    */
13229   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13230   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13231   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13232   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13233   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13234   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13235   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13236   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13237   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13238
13239   /*
13240    * Check the resulting matrix is OK.
13241    */
13242   det = (RQ[0][0] * ST[0][0])
13243       + (RQ[0][1] * ST[0][1])
13244       + (RQ[0][2] * ST[0][2]);
13245   if (!det)
13246     return FALSE;
13247
13248   /*
13249    * Now transform our point with the ST matrix; the notional w
13250    * coordinate is 1, hence the last part is simply added.
13251    */
13252   xi = (int) x;
13253   yi = (int) y;
13254
13255   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13256   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13257   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13258
13259   if (x_out)
13260     *x_out = xf / wf;
13261
13262   if (y_out)
13263     *y_out = yf / wf;
13264
13265 #undef UX2FP
13266 #undef DET2FP
13267
13268   return TRUE;
13269 }
13270
13271 /*
13272  * ClutterGeometry
13273  */
13274
13275 static ClutterGeometry*
13276 clutter_geometry_copy (const ClutterGeometry *geometry)
13277 {
13278   return g_slice_dup (ClutterGeometry, geometry);
13279 }
13280
13281 static void
13282 clutter_geometry_free (ClutterGeometry *geometry)
13283 {
13284   if (G_LIKELY (geometry != NULL))
13285     g_slice_free (ClutterGeometry, geometry);
13286 }
13287
13288 /**
13289  * clutter_geometry_union:
13290  * @geometry_a: a #ClutterGeometry
13291  * @geometry_b: another #ClutterGeometry
13292  * @result: (out): location to store the result
13293  *
13294  * Find the union of two rectangles represented as #ClutterGeometry.
13295  *
13296  * Since: 1.4
13297  */
13298 void
13299 clutter_geometry_union (const ClutterGeometry *geometry_a,
13300                         const ClutterGeometry *geometry_b,
13301                         ClutterGeometry       *result)
13302 {
13303   /* We don't try to handle rectangles that can't be represented
13304    * as a signed integer box */
13305   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13306   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13307   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13308                   geometry_b->x + (gint)geometry_b->width);
13309   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13310                   geometry_b->y + (gint)geometry_b->height);
13311   result->x = x_1;
13312   result->y = y_1;
13313   result->width = x_2 - x_1;
13314   result->height = y_2 - y_1;
13315 }
13316
13317 /**
13318  * clutter_geometry_intersects:
13319  * @geometry0: The first geometry to test
13320  * @geometry1: The second geometry to test
13321  *
13322  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13323  * they do else %FALSE.
13324  *
13325  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13326  * %FALSE.
13327  *
13328  * Since: 1.4
13329  */
13330 gboolean
13331 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13332                              const ClutterGeometry *geometry1)
13333 {
13334   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13335       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13336       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13337       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13338     return FALSE;
13339   else
13340     return TRUE;
13341 }
13342
13343 static gboolean
13344 clutter_geometry_progress (const GValue *a,
13345                            const GValue *b,
13346                            gdouble       progress,
13347                            GValue       *retval)
13348 {
13349   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13350   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13351   ClutterGeometry res = { 0, };
13352   gint a_width = a_geom->width;
13353   gint b_width = b_geom->width;
13354   gint a_height = a_geom->height;
13355   gint b_height = b_geom->height;
13356
13357   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13358   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13359
13360   res.width = a_width + (b_width - a_width) * progress;
13361   res.height = a_height + (b_height - a_height) * progress;
13362
13363   g_value_set_boxed (retval, &res);
13364
13365   return TRUE;
13366 }
13367
13368 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13369                                clutter_geometry_copy,
13370                                clutter_geometry_free,
13371                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13372
13373 /*
13374  * ClutterVertices
13375  */
13376
13377 /**
13378  * clutter_vertex_new:
13379  * @x: X coordinate
13380  * @y: Y coordinate
13381  * @z: Z coordinate
13382  *
13383  * Creates a new #ClutterVertex for the point in 3D space
13384  * identified by the 3 coordinates @x, @y, @z
13385  *
13386  * Return value: the newly allocate #ClutterVertex. Use
13387  *   clutter_vertex_free() to free the resources
13388  *
13389  * Since: 1.0
13390  */
13391 ClutterVertex *
13392 clutter_vertex_new (gfloat x,
13393                     gfloat y,
13394                     gfloat z)
13395 {
13396   ClutterVertex *vertex;
13397
13398   vertex = g_slice_new (ClutterVertex);
13399   clutter_vertex_init (vertex, x, y, z);
13400
13401   return vertex;
13402 }
13403
13404 /**
13405  * clutter_vertex_init:
13406  * @vertex: a #ClutterVertex
13407  * @x: X coordinate
13408  * @y: Y coordinate
13409  * @z: Z coordinate
13410  *
13411  * Initializes @vertex with the given coordinates.
13412  *
13413  * Since: 1.10
13414  */
13415 void
13416 clutter_vertex_init (ClutterVertex *vertex,
13417                      gfloat         x,
13418                      gfloat         y,
13419                      gfloat         z)
13420 {
13421   g_return_if_fail (vertex != NULL);
13422
13423   vertex->x = x;
13424   vertex->y = y;
13425   vertex->z = z;
13426 }
13427
13428 /**
13429  * clutter_vertex_copy:
13430  * @vertex: a #ClutterVertex
13431  *
13432  * Copies @vertex
13433  *
13434  * Return value: a newly allocated copy of #ClutterVertex. Use
13435  *   clutter_vertex_free() to free the allocated resources
13436  *
13437  * Since: 1.0
13438  */
13439 ClutterVertex *
13440 clutter_vertex_copy (const ClutterVertex *vertex)
13441 {
13442   if (G_LIKELY (vertex != NULL))
13443     return g_slice_dup (ClutterVertex, vertex);
13444
13445   return NULL;
13446 }
13447
13448 /**
13449  * clutter_vertex_free:
13450  * @vertex: a #ClutterVertex
13451  *
13452  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13453  *
13454  * Since: 1.0
13455  */
13456 void
13457 clutter_vertex_free (ClutterVertex *vertex)
13458 {
13459   if (G_UNLIKELY (vertex != NULL))
13460     g_slice_free (ClutterVertex, vertex);
13461 }
13462
13463 /**
13464  * clutter_vertex_equal:
13465  * @vertex_a: a #ClutterVertex
13466  * @vertex_b: a #ClutterVertex
13467  *
13468  * Compares @vertex_a and @vertex_b for equality
13469  *
13470  * Return value: %TRUE if the passed #ClutterVertex are equal
13471  *
13472  * Since: 1.0
13473  */
13474 gboolean
13475 clutter_vertex_equal (const ClutterVertex *vertex_a,
13476                       const ClutterVertex *vertex_b)
13477 {
13478   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13479
13480   if (vertex_a == vertex_b)
13481     return TRUE;
13482
13483   return vertex_a->x == vertex_b->x &&
13484          vertex_a->y == vertex_b->y &&
13485          vertex_a->z == vertex_b->z;
13486 }
13487
13488 static gboolean
13489 clutter_vertex_progress (const GValue *a,
13490                          const GValue *b,
13491                          gdouble       progress,
13492                          GValue       *retval)
13493 {
13494   const ClutterVertex *av = g_value_get_boxed (a);
13495   const ClutterVertex *bv = g_value_get_boxed (b);
13496   ClutterVertex res = { 0, };
13497
13498   res.x = av->x + (bv->x - av->x) * progress;
13499   res.y = av->y + (bv->y - av->y) * progress;
13500   res.z = av->z + (bv->z - av->z) * progress;
13501
13502   g_value_set_boxed (retval, &res);
13503
13504   return TRUE;
13505 }
13506
13507 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13508                                clutter_vertex_copy,
13509                                clutter_vertex_free,
13510                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13511
13512 /**
13513  * clutter_actor_is_rotated:
13514  * @self: a #ClutterActor
13515  *
13516  * Checks whether any rotation is applied to the actor.
13517  *
13518  * Return value: %TRUE if the actor is rotated.
13519  *
13520  * Since: 0.6
13521  */
13522 gboolean
13523 clutter_actor_is_rotated (ClutterActor *self)
13524 {
13525   const ClutterTransformInfo *info;
13526
13527   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13528
13529   info = _clutter_actor_get_transform_info_or_defaults (self);
13530
13531   if (info->rx_angle || info->ry_angle || info->rz_angle)
13532     return TRUE;
13533
13534   return FALSE;
13535 }
13536
13537 /**
13538  * clutter_actor_is_scaled:
13539  * @self: a #ClutterActor
13540  *
13541  * Checks whether the actor is scaled in either dimension.
13542  *
13543  * Return value: %TRUE if the actor is scaled.
13544  *
13545  * Since: 0.6
13546  */
13547 gboolean
13548 clutter_actor_is_scaled (ClutterActor *self)
13549 {
13550   const ClutterTransformInfo *info;
13551
13552   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13553
13554   info = _clutter_actor_get_transform_info_or_defaults (self);
13555
13556   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13557     return TRUE;
13558
13559   return FALSE;
13560 }
13561
13562 ClutterActor *
13563 _clutter_actor_get_stage_internal (ClutterActor *actor)
13564 {
13565   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13566     actor = actor->priv->parent;
13567
13568   return actor;
13569 }
13570
13571 /**
13572  * clutter_actor_get_stage:
13573  * @actor: a #ClutterActor
13574  *
13575  * Retrieves the #ClutterStage where @actor is contained.
13576  *
13577  * Return value: (transfer none) (type Clutter.Stage): the stage
13578  *   containing the actor, or %NULL
13579  *
13580  * Since: 0.8
13581  */
13582 ClutterActor *
13583 clutter_actor_get_stage (ClutterActor *actor)
13584 {
13585   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13586
13587   return _clutter_actor_get_stage_internal (actor);
13588 }
13589
13590 /**
13591  * clutter_actor_allocate_available_size:
13592  * @self: a #ClutterActor
13593  * @x: the actor's X coordinate
13594  * @y: the actor's Y coordinate
13595  * @available_width: the maximum available width, or -1 to use the
13596  *   actor's natural width
13597  * @available_height: the maximum available height, or -1 to use the
13598  *   actor's natural height
13599  * @flags: flags controlling the allocation
13600  *
13601  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13602  * preferred size, but limiting it to the maximum available width
13603  * and height provided.
13604  *
13605  * This function will do the right thing when dealing with the
13606  * actor's request mode.
13607  *
13608  * The implementation of this function is equivalent to:
13609  *
13610  * |[
13611  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13612  *     {
13613  *       clutter_actor_get_preferred_width (self, available_height,
13614  *                                          &amp;min_width,
13615  *                                          &amp;natural_width);
13616  *       width = CLAMP (natural_width, min_width, available_width);
13617  *
13618  *       clutter_actor_get_preferred_height (self, width,
13619  *                                           &amp;min_height,
13620  *                                           &amp;natural_height);
13621  *       height = CLAMP (natural_height, min_height, available_height);
13622  *     }
13623  *   else
13624  *     {
13625  *       clutter_actor_get_preferred_height (self, available_width,
13626  *                                           &amp;min_height,
13627  *                                           &amp;natural_height);
13628  *       height = CLAMP (natural_height, min_height, available_height);
13629  *
13630  *       clutter_actor_get_preferred_width (self, height,
13631  *                                          &amp;min_width,
13632  *                                          &amp;natural_width);
13633  *       width = CLAMP (natural_width, min_width, available_width);
13634  *     }
13635  *
13636  *   box.x1 = x; box.y1 = y;
13637  *   box.x2 = box.x1 + available_width;
13638  *   box.y2 = box.y1 + available_height;
13639  *   clutter_actor_allocate (self, &amp;box, flags);
13640  * ]|
13641  *
13642  * This function can be used by fluid layout managers to allocate
13643  * an actor's preferred size without making it bigger than the area
13644  * available for the container.
13645  *
13646  * Since: 1.0
13647  */
13648 void
13649 clutter_actor_allocate_available_size (ClutterActor           *self,
13650                                        gfloat                  x,
13651                                        gfloat                  y,
13652                                        gfloat                  available_width,
13653                                        gfloat                  available_height,
13654                                        ClutterAllocationFlags  flags)
13655 {
13656   ClutterActorPrivate *priv;
13657   gfloat width, height;
13658   gfloat min_width, min_height;
13659   gfloat natural_width, natural_height;
13660   ClutterActorBox box;
13661
13662   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13663
13664   priv = self->priv;
13665
13666   width = height = 0.0;
13667
13668   switch (priv->request_mode)
13669     {
13670     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13671       clutter_actor_get_preferred_width (self, available_height,
13672                                          &min_width,
13673                                          &natural_width);
13674       width  = CLAMP (natural_width, min_width, available_width);
13675
13676       clutter_actor_get_preferred_height (self, width,
13677                                           &min_height,
13678                                           &natural_height);
13679       height = CLAMP (natural_height, min_height, available_height);
13680       break;
13681
13682     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13683       clutter_actor_get_preferred_height (self, available_width,
13684                                           &min_height,
13685                                           &natural_height);
13686       height = CLAMP (natural_height, min_height, available_height);
13687
13688       clutter_actor_get_preferred_width (self, height,
13689                                          &min_width,
13690                                          &natural_width);
13691       width  = CLAMP (natural_width, min_width, available_width);
13692       break;
13693     }
13694
13695
13696   box.x1 = x;
13697   box.y1 = y;
13698   box.x2 = box.x1 + width;
13699   box.y2 = box.y1 + height;
13700   clutter_actor_allocate (self, &box, flags);
13701 }
13702
13703 /**
13704  * clutter_actor_allocate_preferred_size:
13705  * @self: a #ClutterActor
13706  * @flags: flags controlling the allocation
13707  *
13708  * Allocates the natural size of @self.
13709  *
13710  * This function is a utility call for #ClutterActor implementations
13711  * that allocates the actor's preferred natural size. It can be used
13712  * by fixed layout managers (like #ClutterGroup or so called
13713  * 'composite actors') inside the ClutterActor::allocate
13714  * implementation to give each child exactly how much space it
13715  * requires.
13716  *
13717  * This function is not meant to be used by applications. It is also
13718  * not meant to be used outside the implementation of the
13719  * ClutterActor::allocate virtual function.
13720  *
13721  * Since: 0.8
13722  */
13723 void
13724 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13725                                        ClutterAllocationFlags  flags)
13726 {
13727   gfloat actor_x, actor_y;
13728   gfloat natural_width, natural_height;
13729   ClutterActorBox actor_box;
13730
13731   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13732
13733   actor_x = clutter_actor_get_x (self);
13734   actor_y = clutter_actor_get_y (self);
13735
13736   clutter_actor_get_preferred_size (self,
13737                                     NULL, NULL,
13738                                     &natural_width,
13739                                     &natural_height);
13740
13741   actor_box.x1 = actor_x;
13742   actor_box.y1 = actor_y;
13743   actor_box.x2 = actor_box.x1 + natural_width;
13744   actor_box.y2 = actor_box.y1 + natural_height;
13745
13746   clutter_actor_allocate (self, &actor_box, flags);
13747 }
13748
13749 /**
13750  * clutter_actor_allocate_align_fill:
13751  * @self: a #ClutterActor
13752  * @box: a #ClutterActorBox, containing the available width and height
13753  * @x_align: the horizontal alignment, between 0 and 1
13754  * @y_align: the vertical alignment, between 0 and 1
13755  * @x_fill: whether the actor should fill horizontally
13756  * @y_fill: whether the actor should fill vertically
13757  * @flags: allocation flags to be passed to clutter_actor_allocate()
13758  *
13759  * Allocates @self by taking into consideration the available allocation
13760  * area; an alignment factor on either axis; and whether the actor should
13761  * fill the allocation on either axis.
13762  *
13763  * The @box should contain the available allocation width and height;
13764  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13765  * allocation will be offset by their value.
13766  *
13767  * This function takes into consideration the geometry request specified by
13768  * the #ClutterActor:request-mode property, and the text direction.
13769  *
13770  * This function is useful for fluid layout managers, like #ClutterBinLayout
13771  * or #ClutterTableLayout
13772  *
13773  * Since: 1.4
13774  */
13775 void
13776 clutter_actor_allocate_align_fill (ClutterActor           *self,
13777                                    const ClutterActorBox  *box,
13778                                    gdouble                 x_align,
13779                                    gdouble                 y_align,
13780                                    gboolean                x_fill,
13781                                    gboolean                y_fill,
13782                                    ClutterAllocationFlags  flags)
13783 {
13784   ClutterActorPrivate *priv;
13785   ClutterActorBox allocation = { 0, };
13786   gfloat x_offset, y_offset;
13787   gfloat available_width, available_height;
13788   gfloat child_width, child_height;
13789
13790   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13791   g_return_if_fail (box != NULL);
13792   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13793   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13794
13795   priv = self->priv;
13796
13797   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13798   clutter_actor_box_get_size (box, &available_width, &available_height);
13799
13800   if (available_width < 0)
13801     available_width = 0;
13802
13803   if (available_height < 0)
13804     available_height = 0;
13805
13806   if (x_fill)
13807     {
13808       allocation.x1 = x_offset;
13809       allocation.x2 = allocation.x1 + available_width;
13810     }
13811
13812   if (y_fill)
13813     {
13814       allocation.y1 = y_offset;
13815       allocation.y2 = allocation.y1 + available_height;
13816     }
13817
13818   /* if we are filling horizontally and vertically then we're done */
13819   if (x_fill && y_fill)
13820     goto out;
13821
13822   child_width = child_height = 0.0f;
13823
13824   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13825     {
13826       gfloat min_width, natural_width;
13827       gfloat min_height, natural_height;
13828
13829       clutter_actor_get_preferred_width (self, available_height,
13830                                          &min_width,
13831                                          &natural_width);
13832
13833       child_width = CLAMP (natural_width, min_width, available_width);
13834
13835       if (!y_fill)
13836         {
13837           clutter_actor_get_preferred_height (self, child_width,
13838                                               &min_height,
13839                                               &natural_height);
13840
13841           child_height = CLAMP (natural_height, min_height, available_height);
13842         }
13843     }
13844   else
13845     {
13846       gfloat min_width, natural_width;
13847       gfloat min_height, natural_height;
13848
13849       clutter_actor_get_preferred_height (self, available_width,
13850                                           &min_height,
13851                                           &natural_height);
13852
13853       child_height = CLAMP (natural_height, min_height, available_height);
13854
13855       if (!x_fill)
13856         {
13857           clutter_actor_get_preferred_width (self, child_height,
13858                                              &min_width,
13859                                              &natural_width);
13860
13861           child_width = CLAMP (natural_width, min_width, available_width);
13862         }
13863     }
13864
13865   /* invert the horizontal alignment for RTL languages */
13866   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13867     x_align = 1.0 - x_align;
13868
13869   if (!x_fill)
13870     {
13871       allocation.x1 = x_offset
13872                     + ((available_width - child_width) * x_align);
13873       allocation.x2 = allocation.x1 + child_width;
13874     }
13875
13876   if (!y_fill)
13877     {
13878       allocation.y1 = y_offset
13879                     + ((available_height - child_height) * y_align);
13880       allocation.y2 = allocation.y1 + child_height;
13881     }
13882
13883 out:
13884   clutter_actor_box_clamp_to_pixel (&allocation);
13885   clutter_actor_allocate (self, &allocation, flags);
13886 }
13887
13888 /**
13889  * clutter_actor_grab_key_focus:
13890  * @self: a #ClutterActor
13891  *
13892  * Sets the key focus of the #ClutterStage including @self
13893  * to this #ClutterActor.
13894  *
13895  * Since: 1.0
13896  */
13897 void
13898 clutter_actor_grab_key_focus (ClutterActor *self)
13899 {
13900   ClutterActor *stage;
13901
13902   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13903
13904   stage = _clutter_actor_get_stage_internal (self);
13905   if (stage != NULL)
13906     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13907 }
13908
13909 /**
13910  * clutter_actor_get_pango_context:
13911  * @self: a #ClutterActor
13912  *
13913  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13914  * is already configured using the appropriate font map, resolution
13915  * and font options.
13916  *
13917  * Unlike clutter_actor_create_pango_context(), this context is owend
13918  * by the #ClutterActor and it will be updated each time the options
13919  * stored by the #ClutterBackend change.
13920  *
13921  * You can use the returned #PangoContext to create a #PangoLayout
13922  * and render text using cogl_pango_render_layout() to reuse the
13923  * glyphs cache also used by Clutter.
13924  *
13925  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13926  *   The returned #PangoContext is owned by the actor and should not be
13927  *   unreferenced by the application code
13928  *
13929  * Since: 1.0
13930  */
13931 PangoContext *
13932 clutter_actor_get_pango_context (ClutterActor *self)
13933 {
13934   ClutterActorPrivate *priv;
13935
13936   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13937
13938   priv = self->priv;
13939
13940   if (priv->pango_context != NULL)
13941     return priv->pango_context;
13942
13943   priv->pango_context = _clutter_context_get_pango_context ();
13944   g_object_ref (priv->pango_context);
13945
13946   return priv->pango_context;
13947 }
13948
13949 /**
13950  * clutter_actor_create_pango_context:
13951  * @self: a #ClutterActor
13952  *
13953  * Creates a #PangoContext for the given actor. The #PangoContext
13954  * is already configured using the appropriate font map, resolution
13955  * and font options.
13956  *
13957  * See also clutter_actor_get_pango_context().
13958  *
13959  * Return value: (transfer full): the newly created #PangoContext.
13960  *   Use g_object_unref() on the returned value to deallocate its
13961  *   resources
13962  *
13963  * Since: 1.0
13964  */
13965 PangoContext *
13966 clutter_actor_create_pango_context (ClutterActor *self)
13967 {
13968   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13969
13970   return _clutter_context_create_pango_context ();
13971 }
13972
13973 /**
13974  * clutter_actor_create_pango_layout:
13975  * @self: a #ClutterActor
13976  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13977  *
13978  * Creates a new #PangoLayout from the same #PangoContext used
13979  * by the #ClutterActor. The #PangoLayout is already configured
13980  * with the font map, resolution and font options, and the
13981  * given @text.
13982  *
13983  * If you want to keep around a #PangoLayout created by this
13984  * function you will have to connect to the #ClutterBackend::font-changed
13985  * and #ClutterBackend::resolution-changed signals, and call
13986  * pango_layout_context_changed() in response to them.
13987  *
13988  * Return value: (transfer full): the newly created #PangoLayout.
13989  *   Use g_object_unref() when done
13990  *
13991  * Since: 1.0
13992  */
13993 PangoLayout *
13994 clutter_actor_create_pango_layout (ClutterActor *self,
13995                                    const gchar  *text)
13996 {
13997   PangoContext *context;
13998   PangoLayout *layout;
13999
14000   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14001
14002   context = clutter_actor_get_pango_context (self);
14003   layout = pango_layout_new (context);
14004
14005   if (text)
14006     pango_layout_set_text (layout, text, -1);
14007
14008   return layout;
14009 }
14010
14011 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14012  * ClutterOffscreenEffect.
14013  */
14014 void
14015 _clutter_actor_set_opacity_override (ClutterActor *self,
14016                                      gint          opacity)
14017 {
14018   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14019
14020   self->priv->opacity_override = opacity;
14021 }
14022
14023 gint
14024 _clutter_actor_get_opacity_override (ClutterActor *self)
14025 {
14026   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14027
14028   return self->priv->opacity_override;
14029 }
14030
14031 /* Allows you to disable applying the actors model view transform during
14032  * a paint. Used by ClutterClone. */
14033 void
14034 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14035                                                 gboolean      enable)
14036 {
14037   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14038
14039   self->priv->enable_model_view_transform = enable;
14040 }
14041
14042 void
14043 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14044                                           gboolean      enable)
14045 {
14046   ClutterActorPrivate *priv;
14047
14048   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14049
14050   priv = self->priv;
14051
14052   priv->enable_paint_unmapped = enable;
14053
14054   if (priv->enable_paint_unmapped)
14055     {
14056       /* Make sure that the parents of the widget are realized first;
14057        * otherwise checks in clutter_actor_update_map_state() will
14058        * fail.
14059        */
14060       clutter_actor_realize (self);
14061
14062       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14063     }
14064   else
14065     {
14066       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14067     }
14068 }
14069
14070 static void
14071 clutter_anchor_coord_get_units (ClutterActor      *self,
14072                                 const AnchorCoord *coord,
14073                                 gfloat            *x,
14074                                 gfloat            *y,
14075                                 gfloat            *z)
14076 {
14077   if (coord->is_fractional)
14078     {
14079       gfloat actor_width, actor_height;
14080
14081       clutter_actor_get_size (self, &actor_width, &actor_height);
14082
14083       if (x)
14084         *x = actor_width * coord->v.fraction.x;
14085
14086       if (y)
14087         *y = actor_height * coord->v.fraction.y;
14088
14089       if (z)
14090         *z = 0;
14091     }
14092   else
14093     {
14094       if (x)
14095         *x = coord->v.units.x;
14096
14097       if (y)
14098         *y = coord->v.units.y;
14099
14100       if (z)
14101         *z = coord->v.units.z;
14102     }
14103 }
14104
14105 static void
14106 clutter_anchor_coord_set_units (AnchorCoord *coord,
14107                                 gfloat       x,
14108                                 gfloat       y,
14109                                 gfloat       z)
14110 {
14111   coord->is_fractional = FALSE;
14112   coord->v.units.x = x;
14113   coord->v.units.y = y;
14114   coord->v.units.z = z;
14115 }
14116
14117 static ClutterGravity
14118 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14119 {
14120   if (coord->is_fractional)
14121     {
14122       if (coord->v.fraction.x == 0.0)
14123         {
14124           if (coord->v.fraction.y == 0.0)
14125             return CLUTTER_GRAVITY_NORTH_WEST;
14126           else if (coord->v.fraction.y == 0.5)
14127             return CLUTTER_GRAVITY_WEST;
14128           else if (coord->v.fraction.y == 1.0)
14129             return CLUTTER_GRAVITY_SOUTH_WEST;
14130           else
14131             return CLUTTER_GRAVITY_NONE;
14132         }
14133       else if (coord->v.fraction.x == 0.5)
14134         {
14135           if (coord->v.fraction.y == 0.0)
14136             return CLUTTER_GRAVITY_NORTH;
14137           else if (coord->v.fraction.y == 0.5)
14138             return CLUTTER_GRAVITY_CENTER;
14139           else if (coord->v.fraction.y == 1.0)
14140             return CLUTTER_GRAVITY_SOUTH;
14141           else
14142             return CLUTTER_GRAVITY_NONE;
14143         }
14144       else if (coord->v.fraction.x == 1.0)
14145         {
14146           if (coord->v.fraction.y == 0.0)
14147             return CLUTTER_GRAVITY_NORTH_EAST;
14148           else if (coord->v.fraction.y == 0.5)
14149             return CLUTTER_GRAVITY_EAST;
14150           else if (coord->v.fraction.y == 1.0)
14151             return CLUTTER_GRAVITY_SOUTH_EAST;
14152           else
14153             return CLUTTER_GRAVITY_NONE;
14154         }
14155       else
14156         return CLUTTER_GRAVITY_NONE;
14157     }
14158   else
14159     return CLUTTER_GRAVITY_NONE;
14160 }
14161
14162 static void
14163 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14164                                   ClutterGravity  gravity)
14165 {
14166   switch (gravity)
14167     {
14168     case CLUTTER_GRAVITY_NORTH:
14169       coord->v.fraction.x = 0.5;
14170       coord->v.fraction.y = 0.0;
14171       break;
14172
14173     case CLUTTER_GRAVITY_NORTH_EAST:
14174       coord->v.fraction.x = 1.0;
14175       coord->v.fraction.y = 0.0;
14176       break;
14177
14178     case CLUTTER_GRAVITY_EAST:
14179       coord->v.fraction.x = 1.0;
14180       coord->v.fraction.y = 0.5;
14181       break;
14182
14183     case CLUTTER_GRAVITY_SOUTH_EAST:
14184       coord->v.fraction.x = 1.0;
14185       coord->v.fraction.y = 1.0;
14186       break;
14187
14188     case CLUTTER_GRAVITY_SOUTH:
14189       coord->v.fraction.x = 0.5;
14190       coord->v.fraction.y = 1.0;
14191       break;
14192
14193     case CLUTTER_GRAVITY_SOUTH_WEST:
14194       coord->v.fraction.x = 0.0;
14195       coord->v.fraction.y = 1.0;
14196       break;
14197
14198     case CLUTTER_GRAVITY_WEST:
14199       coord->v.fraction.x = 0.0;
14200       coord->v.fraction.y = 0.5;
14201       break;
14202
14203     case CLUTTER_GRAVITY_NORTH_WEST:
14204       coord->v.fraction.x = 0.0;
14205       coord->v.fraction.y = 0.0;
14206       break;
14207
14208     case CLUTTER_GRAVITY_CENTER:
14209       coord->v.fraction.x = 0.5;
14210       coord->v.fraction.y = 0.5;
14211       break;
14212
14213     default:
14214       coord->v.fraction.x = 0.0;
14215       coord->v.fraction.y = 0.0;
14216       break;
14217     }
14218
14219   coord->is_fractional = TRUE;
14220 }
14221
14222 static gboolean
14223 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14224 {
14225   if (coord->is_fractional)
14226     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14227   else
14228     return (coord->v.units.x == 0.0
14229             && coord->v.units.y == 0.0
14230             && coord->v.units.z == 0.0);
14231 }
14232
14233 /**
14234  * clutter_actor_get_flags:
14235  * @self: a #ClutterActor
14236  *
14237  * Retrieves the flags set on @self
14238  *
14239  * Return value: a bitwise or of #ClutterActorFlags or 0
14240  *
14241  * Since: 1.0
14242  */
14243 ClutterActorFlags
14244 clutter_actor_get_flags (ClutterActor *self)
14245 {
14246   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14247
14248   return self->flags;
14249 }
14250
14251 /**
14252  * clutter_actor_set_flags:
14253  * @self: a #ClutterActor
14254  * @flags: the flags to set
14255  *
14256  * Sets @flags on @self
14257  *
14258  * This function will emit notifications for the changed properties
14259  *
14260  * Since: 1.0
14261  */
14262 void
14263 clutter_actor_set_flags (ClutterActor      *self,
14264                          ClutterActorFlags  flags)
14265 {
14266   ClutterActorFlags old_flags;
14267   GObject *obj;
14268   gboolean was_reactive_set, reactive_set;
14269   gboolean was_realized_set, realized_set;
14270   gboolean was_mapped_set, mapped_set;
14271   gboolean was_visible_set, visible_set;
14272
14273   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14274
14275   if (self->flags == flags)
14276     return;
14277
14278   obj = G_OBJECT (self);
14279   g_object_ref (obj);
14280   g_object_freeze_notify (obj);
14281
14282   old_flags = self->flags;
14283
14284   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14285   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14286   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14287   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14288
14289   self->flags |= flags;
14290
14291   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14292   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14293   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14294   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14295
14296   if (reactive_set != was_reactive_set)
14297     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14298
14299   if (realized_set != was_realized_set)
14300     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14301
14302   if (mapped_set != was_mapped_set)
14303     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14304
14305   if (visible_set != was_visible_set)
14306     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14307
14308   g_object_thaw_notify (obj);
14309   g_object_unref (obj);
14310 }
14311
14312 /**
14313  * clutter_actor_unset_flags:
14314  * @self: a #ClutterActor
14315  * @flags: the flags to unset
14316  *
14317  * Unsets @flags on @self
14318  *
14319  * This function will emit notifications for the changed properties
14320  *
14321  * Since: 1.0
14322  */
14323 void
14324 clutter_actor_unset_flags (ClutterActor      *self,
14325                            ClutterActorFlags  flags)
14326 {
14327   ClutterActorFlags old_flags;
14328   GObject *obj;
14329   gboolean was_reactive_set, reactive_set;
14330   gboolean was_realized_set, realized_set;
14331   gboolean was_mapped_set, mapped_set;
14332   gboolean was_visible_set, visible_set;
14333
14334   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14335
14336   obj = G_OBJECT (self);
14337   g_object_freeze_notify (obj);
14338
14339   old_flags = self->flags;
14340
14341   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14342   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14343   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14344   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14345
14346   self->flags &= ~flags;
14347
14348   if (self->flags == old_flags)
14349     return;
14350
14351   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14352   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14353   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14354   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14355
14356   if (reactive_set != was_reactive_set)
14357     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14358
14359   if (realized_set != was_realized_set)
14360     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14361
14362   if (mapped_set != was_mapped_set)
14363     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14364
14365   if (visible_set != was_visible_set)
14366     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14367
14368   g_object_thaw_notify (obj);
14369 }
14370
14371 /**
14372  * clutter_actor_get_transformation_matrix:
14373  * @self: a #ClutterActor
14374  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14375  *
14376  * Retrieves the transformations applied to @self relative to its
14377  * parent.
14378  *
14379  * Since: 1.0
14380  */
14381 void
14382 clutter_actor_get_transformation_matrix (ClutterActor *self,
14383                                          CoglMatrix   *matrix)
14384 {
14385   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14386
14387   cogl_matrix_init_identity (matrix);
14388
14389   _clutter_actor_apply_modelview_transform (self, matrix);
14390 }
14391
14392 void
14393 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14394                                    gboolean      is_in_clone_paint)
14395 {
14396   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14397   self->priv->in_clone_paint = is_in_clone_paint;
14398 }
14399
14400 /**
14401  * clutter_actor_is_in_clone_paint:
14402  * @self: a #ClutterActor
14403  *
14404  * Checks whether @self is being currently painted by a #ClutterClone
14405  *
14406  * This function is useful only inside the ::paint virtual function
14407  * implementations or within handlers for the #ClutterActor::paint
14408  * signal
14409  *
14410  * This function should not be used by applications
14411  *
14412  * Return value: %TRUE if the #ClutterActor is currently being painted
14413  *   by a #ClutterClone, and %FALSE otherwise
14414  *
14415  * Since: 1.0
14416  */
14417 gboolean
14418 clutter_actor_is_in_clone_paint (ClutterActor *self)
14419 {
14420   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14421
14422   return self->priv->in_clone_paint;
14423 }
14424
14425 static gboolean
14426 set_direction_recursive (ClutterActor *actor,
14427                          gpointer      user_data)
14428 {
14429   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14430
14431   clutter_actor_set_text_direction (actor, text_dir);
14432
14433   return TRUE;
14434 }
14435
14436 /**
14437  * clutter_actor_set_text_direction:
14438  * @self: a #ClutterActor
14439  * @text_dir: the text direction for @self
14440  *
14441  * Sets the #ClutterTextDirection for an actor
14442  *
14443  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14444  *
14445  * If @self implements #ClutterContainer then this function will recurse
14446  * inside all the children of @self (including the internal ones).
14447  *
14448  * Composite actors not implementing #ClutterContainer, or actors requiring
14449  * special handling when the text direction changes, should connect to
14450  * the #GObject::notify signal for the #ClutterActor:text-direction property
14451  *
14452  * Since: 1.2
14453  */
14454 void
14455 clutter_actor_set_text_direction (ClutterActor         *self,
14456                                   ClutterTextDirection  text_dir)
14457 {
14458   ClutterActorPrivate *priv;
14459
14460   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14461   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14462
14463   priv = self->priv;
14464
14465   if (priv->text_direction != text_dir)
14466     {
14467       priv->text_direction = text_dir;
14468
14469       /* we need to emit the notify::text-direction first, so that
14470        * the sub-classes can catch that and do specific handling of
14471        * the text direction; see clutter_text_direction_changed_cb()
14472        * inside clutter-text.c
14473        */
14474       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14475
14476       _clutter_actor_foreach_child (self, set_direction_recursive,
14477                                     GINT_TO_POINTER (text_dir));
14478
14479       clutter_actor_queue_relayout (self);
14480     }
14481 }
14482
14483 void
14484 _clutter_actor_set_has_pointer (ClutterActor *self,
14485                                 gboolean      has_pointer)
14486 {
14487   ClutterActorPrivate *priv = self->priv;
14488
14489   if (priv->has_pointer != has_pointer)
14490     {
14491       priv->has_pointer = has_pointer;
14492
14493       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14494     }
14495 }
14496
14497 /**
14498  * clutter_actor_get_text_direction:
14499  * @self: a #ClutterActor
14500  *
14501  * Retrieves the value set using clutter_actor_set_text_direction()
14502  *
14503  * If no text direction has been previously set, the default text
14504  * direction, as returned by clutter_get_default_text_direction(), will
14505  * be returned instead
14506  *
14507  * Return value: the #ClutterTextDirection for the actor
14508  *
14509  * Since: 1.2
14510  */
14511 ClutterTextDirection
14512 clutter_actor_get_text_direction (ClutterActor *self)
14513 {
14514   ClutterActorPrivate *priv;
14515
14516   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14517                         CLUTTER_TEXT_DIRECTION_LTR);
14518
14519   priv = self->priv;
14520
14521   /* if no direction has been set yet use the default */
14522   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14523     priv->text_direction = clutter_get_default_text_direction ();
14524
14525   return priv->text_direction;
14526 }
14527
14528 /**
14529  * clutter_actor_push_internal:
14530  * @self: a #ClutterActor
14531  *
14532  * Should be used by actors implementing the #ClutterContainer and with
14533  * internal children added through clutter_actor_set_parent(), for instance:
14534  *
14535  * |[
14536  *   static void
14537  *   my_actor_init (MyActor *self)
14538  *   {
14539  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14540  *
14541  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14542  *
14543  *     /&ast; calling clutter_actor_set_parent() now will result in
14544  *      &ast; the internal flag being set on a child of MyActor
14545  *      &ast;/
14546  *
14547  *     /&ast; internal child - a background texture &ast;/
14548  *     self->priv->background_tex = clutter_texture_new ();
14549  *     clutter_actor_set_parent (self->priv->background_tex,
14550  *                               CLUTTER_ACTOR (self));
14551  *
14552  *     /&ast; internal child - a label &ast;/
14553  *     self->priv->label = clutter_text_new ();
14554  *     clutter_actor_set_parent (self->priv->label,
14555  *                               CLUTTER_ACTOR (self));
14556  *
14557  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14558  *
14559  *     /&ast; calling clutter_actor_set_parent() now will not result in
14560  *      &ast; the internal flag being set on a child of MyActor
14561  *      &ast;/
14562  *   }
14563  * ]|
14564  *
14565  * This function will be used by Clutter to toggle an "internal child"
14566  * flag whenever clutter_actor_set_parent() is called; internal children
14567  * are handled differently by Clutter, specifically when destroying their
14568  * parent.
14569  *
14570  * Call clutter_actor_pop_internal() when you finished adding internal
14571  * children.
14572  *
14573  * Nested calls to clutter_actor_push_internal() are allowed, but each
14574  * one must by followed by a clutter_actor_pop_internal() call.
14575  *
14576  * Since: 1.2
14577  *
14578  * Deprecated: 1.10: All children of an actor are accessible through
14579  *   the #ClutterActor API, and #ClutterActor implements the
14580  *   #ClutterContainer interface, so this function is only useful
14581  *   for legacy containers overriding the default implementation.
14582  */
14583 void
14584 clutter_actor_push_internal (ClutterActor *self)
14585 {
14586   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14587
14588   self->priv->internal_child += 1;
14589 }
14590
14591 /**
14592  * clutter_actor_pop_internal:
14593  * @self: a #ClutterActor
14594  *
14595  * Disables the effects of clutter_actor_push_internal().
14596  *
14597  * Since: 1.2
14598  *
14599  * Deprecated: 1.10: All children of an actor are accessible through
14600  *   the #ClutterActor API. This function is only useful for legacy
14601  *   containers overriding the default implementation of the
14602  *   #ClutterContainer interface.
14603  */
14604 void
14605 clutter_actor_pop_internal (ClutterActor *self)
14606 {
14607   ClutterActorPrivate *priv;
14608
14609   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14610
14611   priv = self->priv;
14612
14613   if (priv->internal_child == 0)
14614     {
14615       g_warning ("Mismatched %s: you need to call "
14616                  "clutter_actor_push_composite() at least once before "
14617                  "calling this function", G_STRFUNC);
14618       return;
14619     }
14620
14621   priv->internal_child -= 1;
14622 }
14623
14624 /**
14625  * clutter_actor_has_pointer:
14626  * @self: a #ClutterActor
14627  *
14628  * Checks whether an actor contains the pointer of a
14629  * #ClutterInputDevice
14630  *
14631  * Return value: %TRUE if the actor contains the pointer, and
14632  *   %FALSE otherwise
14633  *
14634  * Since: 1.2
14635  */
14636 gboolean
14637 clutter_actor_has_pointer (ClutterActor *self)
14638 {
14639   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14640
14641   return self->priv->has_pointer;
14642 }
14643
14644 /* XXX: This is a workaround for not being able to break the ABI of
14645  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14646  * clutter_actor_queue_clipped_redraw() for details.
14647  */
14648 ClutterPaintVolume *
14649 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14650 {
14651   return g_object_get_data (G_OBJECT (self),
14652                             "-clutter-actor-queue-redraw-clip");
14653 }
14654
14655 void
14656 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14657                                       ClutterPaintVolume *clip)
14658 {
14659   g_object_set_data (G_OBJECT (self),
14660                      "-clutter-actor-queue-redraw-clip",
14661                      clip);
14662 }
14663
14664 /**
14665  * clutter_actor_has_allocation:
14666  * @self: a #ClutterActor
14667  *
14668  * Checks if the actor has an up-to-date allocation assigned to
14669  * it. This means that the actor should have an allocation: it's
14670  * visible and has a parent. It also means that there is no
14671  * outstanding relayout request in progress for the actor or its
14672  * children (There might be other outstanding layout requests in
14673  * progress that will cause the actor to get a new allocation
14674  * when the stage is laid out, however).
14675  *
14676  * If this function returns %FALSE, then the actor will normally
14677  * be allocated before it is next drawn on the screen.
14678  *
14679  * Return value: %TRUE if the actor has an up-to-date allocation
14680  *
14681  * Since: 1.4
14682  */
14683 gboolean
14684 clutter_actor_has_allocation (ClutterActor *self)
14685 {
14686   ClutterActorPrivate *priv;
14687
14688   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14689
14690   priv = self->priv;
14691
14692   return priv->parent != NULL &&
14693          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14694          !priv->needs_allocation;
14695 }
14696
14697 /**
14698  * clutter_actor_add_action:
14699  * @self: a #ClutterActor
14700  * @action: a #ClutterAction
14701  *
14702  * Adds @action to the list of actions applied to @self
14703  *
14704  * A #ClutterAction can only belong to one actor at a time
14705  *
14706  * The #ClutterActor will hold a reference on @action until either
14707  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14708  * is called
14709  *
14710  * Since: 1.4
14711  */
14712 void
14713 clutter_actor_add_action (ClutterActor  *self,
14714                           ClutterAction *action)
14715 {
14716   ClutterActorPrivate *priv;
14717
14718   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14719   g_return_if_fail (CLUTTER_IS_ACTION (action));
14720
14721   priv = self->priv;
14722
14723   if (priv->actions == NULL)
14724     {
14725       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14726       priv->actions->actor = self;
14727     }
14728
14729   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14730
14731   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14732 }
14733
14734 /**
14735  * clutter_actor_add_action_with_name:
14736  * @self: a #ClutterActor
14737  * @name: the name to set on the action
14738  * @action: a #ClutterAction
14739  *
14740  * A convenience function for setting the name of a #ClutterAction
14741  * while adding it to the list of actions applied to @self
14742  *
14743  * This function is the logical equivalent of:
14744  *
14745  * |[
14746  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14747  *   clutter_actor_add_action (self, action);
14748  * ]|
14749  *
14750  * Since: 1.4
14751  */
14752 void
14753 clutter_actor_add_action_with_name (ClutterActor  *self,
14754                                     const gchar   *name,
14755                                     ClutterAction *action)
14756 {
14757   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14758   g_return_if_fail (name != NULL);
14759   g_return_if_fail (CLUTTER_IS_ACTION (action));
14760
14761   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14762   clutter_actor_add_action (self, action);
14763 }
14764
14765 /**
14766  * clutter_actor_remove_action:
14767  * @self: a #ClutterActor
14768  * @action: a #ClutterAction
14769  *
14770  * Removes @action from the list of actions applied to @self
14771  *
14772  * The reference held by @self on the #ClutterAction will be released
14773  *
14774  * Since: 1.4
14775  */
14776 void
14777 clutter_actor_remove_action (ClutterActor  *self,
14778                              ClutterAction *action)
14779 {
14780   ClutterActorPrivate *priv;
14781
14782   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14783   g_return_if_fail (CLUTTER_IS_ACTION (action));
14784
14785   priv = self->priv;
14786
14787   if (priv->actions == NULL)
14788     return;
14789
14790   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14791
14792   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14793 }
14794
14795 /**
14796  * clutter_actor_remove_action_by_name:
14797  * @self: a #ClutterActor
14798  * @name: the name of the action to remove
14799  *
14800  * Removes the #ClutterAction with the given name from the list
14801  * of actions applied to @self
14802  *
14803  * Since: 1.4
14804  */
14805 void
14806 clutter_actor_remove_action_by_name (ClutterActor *self,
14807                                      const gchar  *name)
14808 {
14809   ClutterActorPrivate *priv;
14810   ClutterActorMeta *meta;
14811
14812   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14813   g_return_if_fail (name != NULL);
14814
14815   priv = self->priv;
14816
14817   if (priv->actions == NULL)
14818     return;
14819
14820   meta = _clutter_meta_group_get_meta (priv->actions, name);
14821   if (meta == NULL)
14822     return;
14823
14824   _clutter_meta_group_remove_meta (priv->actions, meta);
14825
14826   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14827 }
14828
14829 /**
14830  * clutter_actor_get_actions:
14831  * @self: a #ClutterActor
14832  *
14833  * Retrieves the list of actions applied to @self
14834  *
14835  * Return value: (transfer container) (element-type Clutter.Action): a copy
14836  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14837  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14838  *   allocated by the returned #GList
14839  *
14840  * Since: 1.4
14841  */
14842 GList *
14843 clutter_actor_get_actions (ClutterActor *self)
14844 {
14845   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14846
14847   if (self->priv->actions == NULL)
14848     return NULL;
14849
14850   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14851 }
14852
14853 /**
14854  * clutter_actor_get_action:
14855  * @self: a #ClutterActor
14856  * @name: the name of the action to retrieve
14857  *
14858  * Retrieves the #ClutterAction with the given name in the list
14859  * of actions applied to @self
14860  *
14861  * Return value: (transfer none): a #ClutterAction for the given
14862  *   name, or %NULL. The returned #ClutterAction is owned by the
14863  *   actor and it should not be unreferenced directly
14864  *
14865  * Since: 1.4
14866  */
14867 ClutterAction *
14868 clutter_actor_get_action (ClutterActor *self,
14869                           const gchar  *name)
14870 {
14871   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14872   g_return_val_if_fail (name != NULL, NULL);
14873
14874   if (self->priv->actions == NULL)
14875     return NULL;
14876
14877   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14878 }
14879
14880 /**
14881  * clutter_actor_clear_actions:
14882  * @self: a #ClutterActor
14883  *
14884  * Clears the list of actions applied to @self
14885  *
14886  * Since: 1.4
14887  */
14888 void
14889 clutter_actor_clear_actions (ClutterActor *self)
14890 {
14891   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14892
14893   if (self->priv->actions == NULL)
14894     return;
14895
14896   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14897 }
14898
14899 /**
14900  * clutter_actor_add_constraint:
14901  * @self: a #ClutterActor
14902  * @constraint: a #ClutterConstraint
14903  *
14904  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14905  * to @self
14906  *
14907  * The #ClutterActor will hold a reference on the @constraint until
14908  * either clutter_actor_remove_constraint() or
14909  * clutter_actor_clear_constraints() is called.
14910  *
14911  * Since: 1.4
14912  */
14913 void
14914 clutter_actor_add_constraint (ClutterActor      *self,
14915                               ClutterConstraint *constraint)
14916 {
14917   ClutterActorPrivate *priv;
14918
14919   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14920   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14921
14922   priv = self->priv;
14923
14924   if (priv->constraints == NULL)
14925     {
14926       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14927       priv->constraints->actor = self;
14928     }
14929
14930   _clutter_meta_group_add_meta (priv->constraints,
14931                                 CLUTTER_ACTOR_META (constraint));
14932   clutter_actor_queue_relayout (self);
14933
14934   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14935 }
14936
14937 /**
14938  * clutter_actor_add_constraint_with_name:
14939  * @self: a #ClutterActor
14940  * @name: the name to set on the constraint
14941  * @constraint: a #ClutterConstraint
14942  *
14943  * A convenience function for setting the name of a #ClutterConstraint
14944  * while adding it to the list of constraints applied to @self
14945  *
14946  * This function is the logical equivalent of:
14947  *
14948  * |[
14949  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14950  *   clutter_actor_add_constraint (self, constraint);
14951  * ]|
14952  *
14953  * Since: 1.4
14954  */
14955 void
14956 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14957                                         const gchar       *name,
14958                                         ClutterConstraint *constraint)
14959 {
14960   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14961   g_return_if_fail (name != NULL);
14962   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14963
14964   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14965   clutter_actor_add_constraint (self, constraint);
14966 }
14967
14968 /**
14969  * clutter_actor_remove_constraint:
14970  * @self: a #ClutterActor
14971  * @constraint: a #ClutterConstraint
14972  *
14973  * Removes @constraint from the list of constraints applied to @self
14974  *
14975  * The reference held by @self on the #ClutterConstraint will be released
14976  *
14977  * Since: 1.4
14978  */
14979 void
14980 clutter_actor_remove_constraint (ClutterActor      *self,
14981                                  ClutterConstraint *constraint)
14982 {
14983   ClutterActorPrivate *priv;
14984
14985   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14986   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14987
14988   priv = self->priv;
14989
14990   if (priv->constraints == NULL)
14991     return;
14992
14993   _clutter_meta_group_remove_meta (priv->constraints,
14994                                    CLUTTER_ACTOR_META (constraint));
14995   clutter_actor_queue_relayout (self);
14996
14997   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14998 }
14999
15000 /**
15001  * clutter_actor_remove_constraint_by_name:
15002  * @self: a #ClutterActor
15003  * @name: the name of the constraint to remove
15004  *
15005  * Removes the #ClutterConstraint with the given name from the list
15006  * of constraints applied to @self
15007  *
15008  * Since: 1.4
15009  */
15010 void
15011 clutter_actor_remove_constraint_by_name (ClutterActor *self,
15012                                          const gchar  *name)
15013 {
15014   ClutterActorPrivate *priv;
15015   ClutterActorMeta *meta;
15016
15017   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15018   g_return_if_fail (name != NULL);
15019
15020   priv = self->priv;
15021
15022   if (priv->constraints == NULL)
15023     return;
15024
15025   meta = _clutter_meta_group_get_meta (priv->constraints, name);
15026   if (meta == NULL)
15027     return;
15028
15029   _clutter_meta_group_remove_meta (priv->constraints, meta);
15030   clutter_actor_queue_relayout (self);
15031 }
15032
15033 /**
15034  * clutter_actor_get_constraints:
15035  * @self: a #ClutterActor
15036  *
15037  * Retrieves the list of constraints applied to @self
15038  *
15039  * Return value: (transfer container) (element-type Clutter.Constraint): a copy
15040  *   of the list of #ClutterConstraint<!-- -->s. The contents of the list are
15041  *   owned by the #ClutterActor. Use g_list_free() to free the resources
15042  *   allocated by the returned #GList
15043  *
15044  * Since: 1.4
15045  */
15046 GList *
15047 clutter_actor_get_constraints (ClutterActor *self)
15048 {
15049   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15050
15051   if (self->priv->constraints == NULL)
15052     return NULL;
15053
15054   return _clutter_meta_group_get_metas_no_internal (self->priv->constraints);
15055 }
15056
15057 /**
15058  * clutter_actor_get_constraint:
15059  * @self: a #ClutterActor
15060  * @name: the name of the constraint to retrieve
15061  *
15062  * Retrieves the #ClutterConstraint with the given name in the list
15063  * of constraints applied to @self
15064  *
15065  * Return value: (transfer none): a #ClutterConstraint for the given
15066  *   name, or %NULL. The returned #ClutterConstraint is owned by the
15067  *   actor and it should not be unreferenced directly
15068  *
15069  * Since: 1.4
15070  */
15071 ClutterConstraint *
15072 clutter_actor_get_constraint (ClutterActor *self,
15073                               const gchar  *name)
15074 {
15075   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15076   g_return_val_if_fail (name != NULL, NULL);
15077
15078   if (self->priv->constraints == NULL)
15079     return NULL;
15080
15081   return CLUTTER_CONSTRAINT (_clutter_meta_group_get_meta (self->priv->constraints, name));
15082 }
15083
15084 /**
15085  * clutter_actor_clear_constraints:
15086  * @self: a #ClutterActor
15087  *
15088  * Clears the list of constraints applied to @self
15089  *
15090  * Since: 1.4
15091  */
15092 void
15093 clutter_actor_clear_constraints (ClutterActor *self)
15094 {
15095   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15096
15097   if (self->priv->constraints == NULL)
15098     return;
15099
15100   _clutter_meta_group_clear_metas_no_internal (self->priv->constraints);
15101
15102   clutter_actor_queue_relayout (self);
15103 }
15104
15105 /**
15106  * clutter_actor_set_clip_to_allocation:
15107  * @self: a #ClutterActor
15108  * @clip_set: %TRUE to apply a clip tracking the allocation
15109  *
15110  * Sets whether @self should be clipped to the same size as its
15111  * allocation
15112  *
15113  * Since: 1.4
15114  */
15115 void
15116 clutter_actor_set_clip_to_allocation (ClutterActor *self,
15117                                       gboolean      clip_set)
15118 {
15119   ClutterActorPrivate *priv;
15120
15121   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15122
15123   clip_set = !!clip_set;
15124
15125   priv = self->priv;
15126
15127   if (priv->clip_to_allocation != clip_set)
15128     {
15129       priv->clip_to_allocation = clip_set;
15130
15131       clutter_actor_queue_redraw (self);
15132
15133       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP_TO_ALLOCATION]);
15134     }
15135 }
15136
15137 /**
15138  * clutter_actor_get_clip_to_allocation:
15139  * @self: a #ClutterActor
15140  *
15141  * Retrieves the value set using clutter_actor_set_clip_to_allocation()
15142  *
15143  * Return value: %TRUE if the #ClutterActor is clipped to its allocation
15144  *
15145  * Since: 1.4
15146  */
15147 gboolean
15148 clutter_actor_get_clip_to_allocation (ClutterActor *self)
15149 {
15150   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15151
15152   return self->priv->clip_to_allocation;
15153 }
15154
15155 /**
15156  * clutter_actor_add_effect:
15157  * @self: a #ClutterActor
15158  * @effect: a #ClutterEffect
15159  *
15160  * Adds @effect to the list of #ClutterEffect<!-- -->s applied to @self
15161  *
15162  * The #ClutterActor will hold a reference on the @effect until either
15163  * clutter_actor_remove_effect() or clutter_actor_clear_effects() is
15164  * called.
15165  *
15166  * Since: 1.4
15167  */
15168 void
15169 clutter_actor_add_effect (ClutterActor  *self,
15170                           ClutterEffect *effect)
15171 {
15172   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15173   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15174
15175   _clutter_actor_add_effect_internal (self, effect);
15176
15177   clutter_actor_queue_redraw (self);
15178
15179   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15180 }
15181
15182 /**
15183  * clutter_actor_add_effect_with_name:
15184  * @self: a #ClutterActor
15185  * @name: the name to set on the effect
15186  * @effect: a #ClutterEffect
15187  *
15188  * A convenience function for setting the name of a #ClutterEffect
15189  * while adding it to the list of effectss applied to @self
15190  *
15191  * This function is the logical equivalent of:
15192  *
15193  * |[
15194  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15195  *   clutter_actor_add_effect (self, effect);
15196  * ]|
15197  *
15198  * Since: 1.4
15199  */
15200 void
15201 clutter_actor_add_effect_with_name (ClutterActor  *self,
15202                                     const gchar   *name,
15203                                     ClutterEffect *effect)
15204 {
15205   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15206   g_return_if_fail (name != NULL);
15207   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15208
15209   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (effect), name);
15210   clutter_actor_add_effect (self, effect);
15211 }
15212
15213 /**
15214  * clutter_actor_remove_effect:
15215  * @self: a #ClutterActor
15216  * @effect: a #ClutterEffect
15217  *
15218  * Removes @effect from the list of effects applied to @self
15219  *
15220  * The reference held by @self on the #ClutterEffect will be released
15221  *
15222  * Since: 1.4
15223  */
15224 void
15225 clutter_actor_remove_effect (ClutterActor  *self,
15226                              ClutterEffect *effect)
15227 {
15228   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15229   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
15230
15231   _clutter_actor_remove_effect_internal (self, effect);
15232
15233   clutter_actor_queue_redraw (self);
15234
15235   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EFFECT]);
15236 }
15237
15238 /**
15239  * clutter_actor_remove_effect_by_name:
15240  * @self: a #ClutterActor
15241  * @name: the name of the effect to remove
15242  *
15243  * Removes the #ClutterEffect with the given name from the list
15244  * of effects applied to @self
15245  *
15246  * Since: 1.4
15247  */
15248 void
15249 clutter_actor_remove_effect_by_name (ClutterActor *self,
15250                                      const gchar  *name)
15251 {
15252   ClutterActorPrivate *priv;
15253   ClutterActorMeta *meta;
15254
15255   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15256   g_return_if_fail (name != NULL);
15257
15258   priv = self->priv;
15259
15260   if (priv->effects == NULL)
15261     return;
15262
15263   meta = _clutter_meta_group_get_meta (priv->effects, name);
15264   if (meta == NULL)
15265     return;
15266
15267   clutter_actor_remove_effect (self, CLUTTER_EFFECT (meta));
15268 }
15269
15270 /**
15271  * clutter_actor_get_effects:
15272  * @self: a #ClutterActor
15273  *
15274  * Retrieves the #ClutterEffect<!-- -->s applied on @self, if any
15275  *
15276  * Return value: (transfer container) (element-type Clutter.Effect): a list
15277  *   of #ClutterEffect<!-- -->s, or %NULL. The elements of the returned
15278  *   list are owned by Clutter and they should not be freed. You should
15279  *   free the returned list using g_list_free() when done
15280  *
15281  * Since: 1.4
15282  */
15283 GList *
15284 clutter_actor_get_effects (ClutterActor *self)
15285 {
15286   ClutterActorPrivate *priv;
15287
15288   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15289
15290   priv = self->priv;
15291
15292   if (priv->effects == NULL)
15293     return NULL;
15294
15295   return _clutter_meta_group_get_metas_no_internal (priv->effects);
15296 }
15297
15298 /**
15299  * clutter_actor_get_effect:
15300  * @self: a #ClutterActor
15301  * @name: the name of the effect to retrieve
15302  *
15303  * Retrieves the #ClutterEffect with the given name in the list
15304  * of effects applied to @self
15305  *
15306  * Return value: (transfer none): a #ClutterEffect for the given
15307  *   name, or %NULL. The returned #ClutterEffect is owned by the
15308  *   actor and it should not be unreferenced directly
15309  *
15310  * Since: 1.4
15311  */
15312 ClutterEffect *
15313 clutter_actor_get_effect (ClutterActor *self,
15314                           const gchar  *name)
15315 {
15316   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15317   g_return_val_if_fail (name != NULL, NULL);
15318
15319   if (self->priv->effects == NULL)
15320     return NULL;
15321
15322   return CLUTTER_EFFECT (_clutter_meta_group_get_meta (self->priv->effects, name));
15323 }
15324
15325 /**
15326  * clutter_actor_clear_effects:
15327  * @self: a #ClutterActor
15328  *
15329  * Clears the list of effects applied to @self
15330  *
15331  * Since: 1.4
15332  */
15333 void
15334 clutter_actor_clear_effects (ClutterActor *self)
15335 {
15336   g_return_if_fail (CLUTTER_IS_ACTOR (self));
15337
15338   if (self->priv->effects == NULL)
15339     return;
15340
15341   _clutter_meta_group_clear_metas_no_internal (self->priv->effects);
15342
15343   clutter_actor_queue_redraw (self);
15344 }
15345
15346 /**
15347  * clutter_actor_has_key_focus:
15348  * @self: a #ClutterActor
15349  *
15350  * Checks whether @self is the #ClutterActor that has key focus
15351  *
15352  * Return value: %TRUE if the actor has key focus, and %FALSE otherwise
15353  *
15354  * Since: 1.4
15355  */
15356 gboolean
15357 clutter_actor_has_key_focus (ClutterActor *self)
15358 {
15359   ClutterActor *stage;
15360
15361   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15362
15363   stage = _clutter_actor_get_stage_internal (self);
15364   if (stage == NULL)
15365     return FALSE;
15366
15367   return clutter_stage_get_key_focus (CLUTTER_STAGE (stage)) == self;
15368 }
15369
15370 static gboolean
15371 _clutter_actor_get_paint_volume_real (ClutterActor *self,
15372                                       ClutterPaintVolume *pv)
15373 {
15374   ClutterActorPrivate *priv = self->priv;
15375
15376   /* Actors are only expected to report a valid paint volume
15377    * while they have a valid allocation. */
15378   if (G_UNLIKELY (priv->needs_allocation))
15379     {
15380       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15381                     "Actor needs allocation",
15382                     _clutter_actor_get_debug_name (self));
15383       return FALSE;
15384     }
15385
15386   /* Check if there are any handlers connected to the paint
15387    * signal. If there are then all bets are off for what the paint
15388    * volume for this actor might possibly be!
15389    *
15390    * XXX: It's expected that this is going to end up being quite a
15391    * costly check to have to do here, but we haven't come up with
15392    * another solution that can reliably catch paint signal handlers at
15393    * the right time to either avoid artefacts due to invalid stage
15394    * clipping or due to incorrect culling.
15395    *
15396    * Previously we checked in clutter_actor_paint(), but at that time
15397    * we may already be using a stage clip that could be derived from
15398    * an invalid paint-volume. We used to try and handle that by
15399    * queuing a follow up, unclipped, redraw but still the previous
15400    * checking wasn't enough to catch invalid volumes involved in
15401    * culling (considering that containers may derive their volume from
15402    * children that haven't yet been painted)
15403    *
15404    * Longer term, improved solutions could be:
15405    * - Disallow painting in the paint signal, only allow using it
15406    *   for tracking when paints happen. We can add another API that
15407    *   allows monkey patching the paint of arbitrary actors but in a
15408    *   more controlled way and that also supports modifying the
15409    *   paint-volume.
15410    * - If we could be notified somehow when signal handlers are
15411    *   connected we wouldn't have to poll for handlers like this.
15412    */
15413   if (g_signal_has_handler_pending (self,
15414                                     actor_signals[PAINT],
15415                                     0,
15416                                     TRUE))
15417     {
15418       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15419                     "Actor has \"paint\" signal handlers",
15420                     _clutter_actor_get_debug_name (self));
15421       return FALSE;
15422     }
15423
15424   _clutter_paint_volume_init_static (pv, self);
15425
15426   if (!CLUTTER_ACTOR_GET_CLASS (self)->get_paint_volume (self, pv))
15427     {
15428       clutter_paint_volume_free (pv);
15429       CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15430                     "Actor failed to report a volume",
15431                     _clutter_actor_get_debug_name (self));
15432       return FALSE;
15433     }
15434
15435   /* since effects can modify the paint volume, we allow them to actually
15436    * do this by making get_paint_volume() "context sensitive"
15437    */
15438   if (priv->effects != NULL)
15439     {
15440       if (priv->current_effect != NULL)
15441         {
15442           const GList *effects, *l;
15443
15444           /* if we are being called from within the paint sequence of
15445            * an actor, get the paint volume up to the current effect
15446            */
15447           effects = _clutter_meta_group_peek_metas (priv->effects);
15448           for (l = effects;
15449                l != NULL || (l != NULL && l->data != priv->current_effect);
15450                l = l->next)
15451             {
15452               if (!_clutter_effect_get_paint_volume (l->data, pv))
15453                 {
15454                   clutter_paint_volume_free (pv);
15455                   CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15456                                 "Effect (%s) failed to report a volume",
15457                                 _clutter_actor_get_debug_name (self),
15458                                 _clutter_actor_meta_get_debug_name (l->data));
15459                   return FALSE;
15460                 }
15461             }
15462         }
15463       else
15464         {
15465           const GList *effects, *l;
15466
15467           /* otherwise, get the cumulative volume */
15468           effects = _clutter_meta_group_peek_metas (priv->effects);
15469           for (l = effects; l != NULL; l = l->next)
15470             if (!_clutter_effect_get_paint_volume (l->data, pv))
15471               {
15472                 clutter_paint_volume_free (pv);
15473                 CLUTTER_NOTE (CLIPPING, "Bail from get_paint_volume (%s): "
15474                               "Effect (%s) failed to report a volume",
15475                               _clutter_actor_get_debug_name (self),
15476                               _clutter_actor_meta_get_debug_name (l->data));
15477                 return FALSE;
15478               }
15479         }
15480     }
15481
15482   return TRUE;
15483 }
15484
15485 /* The public clutter_actor_get_paint_volume API returns a const
15486  * pointer since we return a pointer directly to the cached
15487  * PaintVolume associated with the actor and don't want the user to
15488  * inadvertently modify it, but for internal uses we sometimes need
15489  * access to the same PaintVolume but need to apply some book-keeping
15490  * modifications to it so we don't want a const pointer.
15491  */
15492 static ClutterPaintVolume *
15493 _clutter_actor_get_paint_volume_mutable (ClutterActor *self)
15494 {
15495   ClutterActorPrivate *priv;
15496
15497   priv = self->priv;
15498
15499   if (priv->paint_volume_valid)
15500     clutter_paint_volume_free (&priv->paint_volume);
15501
15502   if (_clutter_actor_get_paint_volume_real (self, &priv->paint_volume))
15503     {
15504       priv->paint_volume_valid = TRUE;
15505       return &priv->paint_volume;
15506     }
15507   else
15508     {
15509       priv->paint_volume_valid = FALSE;
15510       return NULL;
15511     }
15512 }
15513
15514 /**
15515  * clutter_actor_get_paint_volume:
15516  * @self: a #ClutterActor
15517  *
15518  * Retrieves the paint volume of the passed #ClutterActor, or %NULL
15519  * when a paint volume can't be determined.
15520  *
15521  * The paint volume is defined as the 3D space occupied by an actor
15522  * when being painted.
15523  *
15524  * This function will call the <function>get_paint_volume()</function>
15525  * virtual function of the #ClutterActor class. Sub-classes of #ClutterActor
15526  * should not usually care about overriding the default implementation,
15527  * unless they are, for instance: painting outside their allocation, or
15528  * actors with a depth factor (not in terms of #ClutterActor:depth but real
15529  * 3D depth).
15530  *
15531  * <note>2D actors overriding <function>get_paint_volume()</function>
15532  * ensure their volume has a depth of 0. (This will be true so long as
15533  * you don't call clutter_paint_volume_set_depth().)</note>
15534  *
15535  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15536  *   or %NULL if no volume could be determined. The returned pointer
15537  *   is not guaranteed to be valid across multiple frames; if you want
15538  *   to keep it, you will need to copy it using clutter_paint_volume_copy().
15539  *
15540  * Since: 1.6
15541  */
15542 const ClutterPaintVolume *
15543 clutter_actor_get_paint_volume (ClutterActor *self)
15544 {
15545   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15546
15547   return _clutter_actor_get_paint_volume_mutable (self);
15548 }
15549
15550 /**
15551  * clutter_actor_get_transformed_paint_volume:
15552  * @self: a #ClutterActor
15553  * @relative_to_ancestor: A #ClutterActor that is an ancestor of @self
15554  *    (or %NULL for the stage)
15555  *
15556  * Retrieves the 3D paint volume of an actor like
15557  * clutter_actor_get_paint_volume() does (Please refer to the
15558  * documentation of clutter_actor_get_paint_volume() for more
15559  * details.) and it additionally transforms the paint volume into the
15560  * coordinate space of @relative_to_ancestor. (Or the stage if %NULL
15561  * is passed for @relative_to_ancestor)
15562  *
15563  * This can be used by containers that base their paint volume on
15564  * the volume of their children. Such containers can query the
15565  * transformed paint volume of all of its children and union them
15566  * together using clutter_paint_volume_union().
15567  *
15568  * Return value: (transfer none): a pointer to a #ClutterPaintVolume,
15569  *   or %NULL if no volume could be determined. The returned pointer is
15570  *   not guaranteed to be valid across multiple frames; if you wish to
15571  *   keep it, you will have to copy it using clutter_paint_volume_copy().
15572  *
15573  * Since: 1.6
15574  */
15575 const ClutterPaintVolume *
15576 clutter_actor_get_transformed_paint_volume (ClutterActor *self,
15577                                             ClutterActor *relative_to_ancestor)
15578 {
15579   const ClutterPaintVolume *volume;
15580   ClutterActor *stage;
15581   ClutterPaintVolume *transformed_volume;
15582
15583   stage = _clutter_actor_get_stage_internal (self);
15584   if (G_UNLIKELY (stage == NULL))
15585     return NULL;
15586
15587   if (relative_to_ancestor == NULL)
15588     relative_to_ancestor = stage;
15589
15590   volume = clutter_actor_get_paint_volume (self);
15591   if (volume == NULL)
15592     return NULL;
15593
15594   transformed_volume =
15595     _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
15596
15597   _clutter_paint_volume_copy_static (volume, transformed_volume);
15598
15599   _clutter_paint_volume_transform_relative (transformed_volume,
15600                                             relative_to_ancestor);
15601
15602   return transformed_volume;
15603 }
15604
15605 /**
15606  * clutter_actor_get_paint_box:
15607  * @self: a #ClutterActor
15608  * @box: (out): return location for a #ClutterActorBox
15609  *
15610  * Retrieves the paint volume of the passed #ClutterActor, and
15611  * transforms it into a 2D bounding box in stage coordinates.
15612  *
15613  * This function is useful to determine the on screen area occupied by
15614  * the actor. The box is only an approximation and may often be
15615  * considerably larger due to the optimizations used to calculate the
15616  * box. The box is never smaller though, so it can reliably be used
15617  * for culling.
15618  *
15619  * There are times when a 2D paint box can't be determined, e.g.
15620  * because the actor isn't yet parented under a stage or because
15621  * the actor is unable to determine a paint volume.
15622  *
15623  * Return value: %TRUE if a 2D paint box could be determined, else
15624  * %FALSE.
15625  *
15626  * Since: 1.6
15627  */
15628 gboolean
15629 clutter_actor_get_paint_box (ClutterActor    *self,
15630                              ClutterActorBox *box)
15631 {
15632   ClutterActor *stage;
15633   ClutterPaintVolume *pv;
15634
15635   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
15636   g_return_val_if_fail (box != NULL, FALSE);
15637
15638   stage = _clutter_actor_get_stage_internal (self);
15639   if (G_UNLIKELY (!stage))
15640     return FALSE;
15641
15642   pv = _clutter_actor_get_paint_volume_mutable (self);
15643   if (G_UNLIKELY (!pv))
15644     return FALSE;
15645
15646   _clutter_paint_volume_get_stage_paint_box (pv, CLUTTER_STAGE (stage), box);
15647
15648   return TRUE;
15649 }
15650
15651 /**
15652  * clutter_actor_has_overlaps:
15653  * @self: A #ClutterActor
15654  *
15655  * Asks the actor's implementation whether it may contain overlapping
15656  * primitives.
15657  *
15658  * For example; Clutter may use this to determine whether the painting
15659  * should be redirected to an offscreen buffer to correctly implement
15660  * the opacity property.
15661  *
15662  * Custom actors can override the default response by implementing the
15663  * #ClutterActor <function>has_overlaps</function> virtual function. See
15664  * clutter_actor_set_offscreen_redirect() for more information.
15665  *
15666  * Return value: %TRUE if the actor may have overlapping primitives, and
15667  *   %FALSE otherwise
15668  *
15669  * Since: 1.8
15670  */
15671 gboolean
15672 clutter_actor_has_overlaps (ClutterActor *self)
15673 {
15674   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15675
15676   return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
15677 }
15678
15679 /**
15680  * clutter_actor_has_effects:
15681  * @self: A #ClutterActor
15682  *
15683  * Returns whether the actor has any effects applied.
15684  *
15685  * Return value: %TRUE if the actor has any effects,
15686  *   %FALSE otherwise
15687  *
15688  * Since: 1.10
15689  */
15690 gboolean
15691 clutter_actor_has_effects (ClutterActor *self)
15692 {
15693   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15694
15695   if (self->priv->effects == NULL)
15696     return FALSE;
15697
15698   return _clutter_meta_group_has_metas_no_internal (self->priv->effects);
15699 }
15700
15701 /**
15702  * clutter_actor_has_constraints:
15703  * @self: A #ClutterActor
15704  *
15705  * Returns whether the actor has any constraints applied.
15706  *
15707  * Return value: %TRUE if the actor has any constraints,
15708  *   %FALSE otherwise
15709  *
15710  * Since: 1.10
15711  */
15712 gboolean
15713 clutter_actor_has_constraints (ClutterActor *self)
15714 {
15715   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15716
15717   return self->priv->constraints != NULL;
15718 }
15719
15720 /**
15721  * clutter_actor_has_actions:
15722  * @self: A #ClutterActor
15723  *
15724  * Returns whether the actor has any actions applied.
15725  *
15726  * Return value: %TRUE if the actor has any actions,
15727  *   %FALSE otherwise
15728  *
15729  * Since: 1.10
15730  */
15731 gboolean
15732 clutter_actor_has_actions (ClutterActor *self)
15733 {
15734   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
15735
15736   return self->priv->actions != NULL;
15737 }
15738
15739 /**
15740  * clutter_actor_get_n_children:
15741  * @self: a #ClutterActor
15742  *
15743  * Retrieves the number of children of @self.
15744  *
15745  * Return value: the number of children of an actor
15746  *
15747  * Since: 1.10
15748  */
15749 gint
15750 clutter_actor_get_n_children (ClutterActor *self)
15751 {
15752   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
15753
15754   return self->priv->n_children;
15755 }
15756
15757 /**
15758  * clutter_actor_get_child_at_index:
15759  * @self: a #ClutterActor
15760  * @index_: the position in the list of children
15761  *
15762  * Retrieves the actor at the given @index_ inside the list of
15763  * children of @self.
15764  *
15765  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
15766  *
15767  * Since: 1.10
15768  */
15769 ClutterActor *
15770 clutter_actor_get_child_at_index (ClutterActor *self,
15771                                   gint          index_)
15772 {
15773   ClutterActor *iter;
15774   int i;
15775
15776   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
15777   g_return_val_if_fail (index_ <= self->priv->n_children, NULL);
15778
15779   for (iter = self->priv->first_child, i = 0;
15780        iter != NULL && i < index_;
15781        iter = iter->priv->next_sibling, i += 1)
15782     ;
15783
15784   return iter;
15785 }
15786
15787 /*< private >
15788  * _clutter_actor_foreach_child:
15789  * @actor: The actor whos children you want to iterate
15790  * @callback: The function to call for each child
15791  * @user_data: Private data to pass to @callback
15792  *
15793  * Calls a given @callback once for each child of the specified @actor and
15794  * passing the @user_data pointer each time.
15795  *
15796  * Return value: returns %TRUE if all children were iterated, else
15797  *    %FALSE if a callback broke out of iteration early.
15798  */
15799 gboolean
15800 _clutter_actor_foreach_child (ClutterActor           *self,
15801                               ClutterForeachCallback  callback,
15802                               gpointer                user_data)
15803 {
15804   ClutterActor *iter;
15805   gboolean cont;
15806
15807   if (self->priv->first_child == NULL)
15808     return TRUE;
15809
15810   cont = TRUE;
15811   iter = self->priv->first_child;
15812
15813   /* we use this form so that it's safe to change the children
15814    * list while iterating it
15815    */
15816   while (cont && iter != NULL)
15817     {
15818       ClutterActor *next = iter->priv->next_sibling;
15819
15820       cont = callback (iter, user_data);
15821
15822       iter = next;
15823     }
15824
15825   return cont;
15826 }
15827
15828 #if 0
15829 /* For debugging purposes this gives us a simple way to print out
15830  * the scenegraph e.g in gdb using:
15831  * [|
15832  *   _clutter_actor_traverse (stage,
15833  *                            0,
15834  *                            clutter_debug_print_actor_cb,
15835  *                            NULL,
15836  *                            NULL);
15837  * |]
15838  */
15839 static ClutterActorTraverseVisitFlags
15840 clutter_debug_print_actor_cb (ClutterActor *actor,
15841                               int depth,
15842                               void *user_data)
15843 {
15844   g_print ("%*s%s:%p\n",
15845            depth * 2, "",
15846            _clutter_actor_get_debug_name (actor),
15847            actor);
15848
15849   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15850 }
15851 #endif
15852
15853 static void
15854 _clutter_actor_traverse_breadth (ClutterActor           *actor,
15855                                  ClutterTraverseCallback callback,
15856                                  gpointer                user_data)
15857 {
15858   GQueue *queue = g_queue_new ();
15859   ClutterActor dummy;
15860   int current_depth = 0;
15861
15862   g_queue_push_tail (queue, actor);
15863   g_queue_push_tail (queue, &dummy); /* use to delimit depth changes */
15864
15865   while ((actor = g_queue_pop_head (queue)))
15866     {
15867       ClutterActorTraverseVisitFlags flags;
15868
15869       if (actor == &dummy)
15870         {
15871           current_depth++;
15872           g_queue_push_tail (queue, &dummy);
15873           continue;
15874         }
15875
15876       flags = callback (actor, current_depth, user_data);
15877       if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15878         break;
15879       else if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15880         {
15881           ClutterActor *iter;
15882
15883           for (iter = actor->priv->first_child;
15884                iter != NULL;
15885                iter = iter->priv->next_sibling)
15886             {
15887               g_queue_push_tail (queue, iter);
15888             }
15889         }
15890     }
15891
15892   g_queue_free (queue);
15893 }
15894
15895 static ClutterActorTraverseVisitFlags
15896 _clutter_actor_traverse_depth (ClutterActor           *actor,
15897                                ClutterTraverseCallback before_children_callback,
15898                                ClutterTraverseCallback after_children_callback,
15899                                int                     current_depth,
15900                                gpointer                user_data)
15901 {
15902   ClutterActorTraverseVisitFlags flags;
15903
15904   flags = before_children_callback (actor, current_depth, user_data);
15905   if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15906     return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15907
15908   if (!(flags & CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN))
15909     {
15910       ClutterActor *iter;
15911
15912       for (iter = actor->priv->first_child;
15913            iter != NULL;
15914            iter = iter->priv->next_sibling)
15915         {
15916           flags = _clutter_actor_traverse_depth (iter,
15917                                                  before_children_callback,
15918                                                  after_children_callback,
15919                                                  current_depth + 1,
15920                                                  user_data);
15921
15922           if (flags & CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK)
15923             return CLUTTER_ACTOR_TRAVERSE_VISIT_BREAK;
15924         }
15925     }
15926
15927   if (after_children_callback)
15928     return after_children_callback (actor, current_depth, user_data);
15929   else
15930     return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
15931 }
15932
15933 /* _clutter_actor_traverse:
15934  * @actor: The actor to start traversing the graph from
15935  * @flags: These flags may affect how the traversal is done
15936  * @before_children_callback: A function to call before visiting the
15937  *   children of the current actor.
15938  * @after_children_callback: A function to call after visiting the
15939  *   children of the current actor. (Ignored if
15940  *   %CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST is passed to @flags.)
15941  * @user_data: The private data to pass to the callbacks
15942  *
15943  * Traverses the scenegraph starting at the specified @actor and
15944  * descending through all its children and its children's children.
15945  * For each actor traversed @before_children_callback and
15946  * @after_children_callback are called with the specified
15947  * @user_data, before and after visiting that actor's children.
15948  *
15949  * The callbacks can return flags that affect the ongoing traversal
15950  * such as by skipping over an actors children or bailing out of
15951  * any further traversing.
15952  */
15953 void
15954 _clutter_actor_traverse (ClutterActor              *actor,
15955                          ClutterActorTraverseFlags  flags,
15956                          ClutterTraverseCallback    before_children_callback,
15957                          ClutterTraverseCallback    after_children_callback,
15958                          gpointer                   user_data)
15959 {
15960   if (flags & CLUTTER_ACTOR_TRAVERSE_BREADTH_FIRST)
15961     _clutter_actor_traverse_breadth (actor,
15962                                      before_children_callback,
15963                                      user_data);
15964   else /* DEPTH_FIRST */
15965     _clutter_actor_traverse_depth (actor,
15966                                    before_children_callback,
15967                                    after_children_callback,
15968                                    0, /* start depth */
15969                                    user_data);
15970 }
15971
15972 static void
15973 on_layout_manager_changed (ClutterLayoutManager *manager,
15974                            ClutterActor         *self)
15975 {
15976   clutter_actor_queue_relayout (self);
15977 }
15978
15979 /**
15980  * clutter_actor_set_layout_manager:
15981  * @self: a #ClutterActor
15982  * @manager: (allow-none): a #ClutterLayoutManager, or %NULL to unset it
15983  *
15984  * Sets the #ClutterLayoutManager delegate object that will be used to
15985  * lay out the children of @self.
15986  *
15987  * The #ClutterActor will take a reference on the passed @manager which
15988  * will be released either when the layout manager is removed, or when
15989  * the actor is destroyed.
15990  *
15991  * Since: 1.10
15992  */
15993 void
15994 clutter_actor_set_layout_manager (ClutterActor         *self,
15995                                   ClutterLayoutManager *manager)
15996 {
15997   ClutterActorPrivate *priv;
15998
15999   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16000   g_return_if_fail (manager == NULL || CLUTTER_IS_LAYOUT_MANAGER (manager));
16001
16002   priv = self->priv;
16003
16004   if (priv->layout_manager != NULL)
16005     {
16006       g_signal_handlers_disconnect_by_func (priv->layout_manager,
16007                                             G_CALLBACK (on_layout_manager_changed),
16008                                             self);
16009       clutter_layout_manager_set_container (priv->layout_manager, NULL);
16010       g_clear_object (&priv->layout_manager);
16011     }
16012
16013   priv->layout_manager = manager;
16014
16015   if (priv->layout_manager != NULL)
16016     {
16017       g_object_ref_sink (priv->layout_manager);
16018       clutter_layout_manager_set_container (priv->layout_manager,
16019                                             CLUTTER_CONTAINER (self));
16020       g_signal_connect (priv->layout_manager, "layout-changed",
16021                         G_CALLBACK (on_layout_manager_changed),
16022                         self);
16023     }
16024
16025   clutter_actor_queue_relayout (self);
16026
16027   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAYOUT_MANAGER]);
16028 }
16029
16030 /**
16031  * clutter_actor_get_layout_manager:
16032  * @self: a #ClutterActor
16033  *
16034  * Retrieves the #ClutterLayoutManager used by @self.
16035  *
16036  * Return value: (transfer none): a pointer to the #ClutterLayoutManager,
16037  *   or %NULL
16038  *
16039  * Since: 1.10
16040  */
16041 ClutterLayoutManager *
16042 clutter_actor_get_layout_manager (ClutterActor *self)
16043 {
16044   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16045
16046   return self->priv->layout_manager;
16047 }
16048
16049 static const ClutterLayoutInfo default_layout_info = {
16050   0.f,                          /* fixed-x */
16051   0.f,                          /* fixed-y */
16052   { 0, 0, 0, 0 },               /* margin */
16053   CLUTTER_ACTOR_ALIGN_FILL,     /* x-align */
16054   CLUTTER_ACTOR_ALIGN_FILL,     /* y-align */
16055   0.f, 0.f,                     /* min_width, natural_width */
16056   0.f, 0.f,                     /* natual_width, natural_height */
16057 };
16058
16059 static void
16060 layout_info_free (gpointer data)
16061 {
16062   if (G_LIKELY (data != NULL))
16063     g_slice_free (ClutterLayoutInfo, data);
16064 }
16065
16066 /*< private >
16067  * _clutter_actor_get_layout_info:
16068  * @self: a #ClutterActor
16069  *
16070  * Retrieves a pointer to the ClutterLayoutInfo structure.
16071  *
16072  * If the actor does not have a ClutterLayoutInfo associated to it, one
16073  * will be created and initialized to the default values.
16074  *
16075  * This function should be used for setters.
16076  *
16077  * For getters, you should use _clutter_actor_get_layout_info_or_defaults()
16078  * instead.
16079  *
16080  * Return value: (transfer none): a pointer to the ClutterLayoutInfo structure
16081  */
16082 ClutterLayoutInfo *
16083 _clutter_actor_get_layout_info (ClutterActor *self)
16084 {
16085   ClutterLayoutInfo *retval;
16086
16087   retval = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16088   if (retval == NULL)
16089     {
16090       retval = g_slice_new (ClutterLayoutInfo);
16091
16092       *retval = default_layout_info;
16093
16094       g_object_set_qdata_full (G_OBJECT (self), quark_actor_layout_info,
16095                                retval,
16096                                layout_info_free);
16097     }
16098
16099   return retval;
16100 }
16101
16102 /*< private >
16103  * _clutter_actor_get_layout_info_or_defaults:
16104  * @self: a #ClutterActor
16105  *
16106  * Retrieves the ClutterLayoutInfo structure associated to an actor.
16107  *
16108  * If the actor does not have a ClutterLayoutInfo structure associated to it,
16109  * then the default structure will be returned.
16110  *
16111  * This function should only be used for getters.
16112  *
16113  * Return value: a const pointer to the ClutterLayoutInfo structure
16114  */
16115 const ClutterLayoutInfo *
16116 _clutter_actor_get_layout_info_or_defaults (ClutterActor *self)
16117 {
16118   const ClutterLayoutInfo *info;
16119
16120   info = g_object_get_qdata (G_OBJECT (self), quark_actor_layout_info);
16121   if (info == NULL)
16122     return &default_layout_info;
16123
16124   return info;
16125 }
16126
16127 /**
16128  * clutter_actor_set_x_align:
16129  * @self: a #ClutterActor
16130  * @x_align: the horizontal alignment policy
16131  *
16132  * Sets the horizontal alignment policy of a #ClutterActor, in case the
16133  * actor received extra horizontal space.
16134  *
16135  * See also the #ClutterActor:x-align property.
16136  *
16137  * Since: 1.10
16138  */
16139 void
16140 clutter_actor_set_x_align (ClutterActor      *self,
16141                            ClutterActorAlign  x_align)
16142 {
16143   ClutterLayoutInfo *info;
16144
16145   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16146
16147   info = _clutter_actor_get_layout_info (self);
16148
16149   if (info->x_align != x_align)
16150     {
16151       info->x_align = x_align;
16152
16153       clutter_actor_queue_relayout (self);
16154
16155       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_X_ALIGN]);
16156     }
16157 }
16158
16159 /**
16160  * clutter_actor_get_x_align:
16161  * @self: a #ClutterActor
16162  *
16163  * Retrieves the horizontal alignment policy set using
16164  * clutter_actor_set_x_align().
16165  *
16166  * Return value: the horizontal alignment policy.
16167  *
16168  * Since: 1.10
16169  */
16170 ClutterActorAlign
16171 clutter_actor_get_x_align (ClutterActor *self)
16172 {
16173   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16174
16175   return _clutter_actor_get_layout_info_or_defaults (self)->x_align;
16176 }
16177
16178 /**
16179  * clutter_actor_set_y_align:
16180  * @self: a #ClutterActor
16181  * @y_align: the vertical alignment policy
16182  *
16183  * Sets the vertical alignment policy of a #ClutterActor, in case the
16184  * actor received extra vertical space.
16185  *
16186  * See also the #ClutterActor:y-align property.
16187  *
16188  * Since: 1.10
16189  */
16190 void
16191 clutter_actor_set_y_align (ClutterActor      *self,
16192                            ClutterActorAlign  y_align)
16193 {
16194   ClutterLayoutInfo *info;
16195
16196   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16197
16198   info = _clutter_actor_get_layout_info (self);
16199
16200   if (info->y_align != y_align)
16201     {
16202       info->y_align = y_align;
16203
16204       clutter_actor_queue_relayout (self);
16205
16206       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_Y_ALIGN]);
16207     }
16208 }
16209
16210 /**
16211  * clutter_actor_get_y_align:
16212  * @self: a #ClutterActor
16213  *
16214  * Retrieves the vertical alignment policy set using
16215  * clutter_actor_set_y_align().
16216  *
16217  * Return value: the vertical alignment policy.
16218  *
16219  * Since: 1.10
16220  */
16221 ClutterActorAlign
16222 clutter_actor_get_y_align (ClutterActor *self)
16223 {
16224   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_ACTOR_ALIGN_FILL);
16225
16226   return _clutter_actor_get_layout_info_or_defaults (self)->y_align;
16227 }
16228
16229
16230 /**
16231  * clutter_margin_new:
16232  *
16233  * Creates a new #ClutterMargin.
16234  *
16235  * Return value: (transfer full): a newly allocated #ClutterMargin. Use
16236  *   clutter_margin_free() to free the resources associated with it when
16237  *   done.
16238  *
16239  * Since: 1.10
16240  */
16241 ClutterMargin *
16242 clutter_margin_new (void)
16243 {
16244   return g_slice_new0 (ClutterMargin);
16245 }
16246
16247 /**
16248  * clutter_margin_copy:
16249  * @margin_: a #ClutterMargin
16250  *
16251  * Creates a new #ClutterMargin and copies the contents of @margin_ into
16252  * the newly created structure.
16253  *
16254  * Return value: (transfer full): a copy of the #ClutterMargin.
16255  *
16256  * Since: 1.10
16257  */
16258 ClutterMargin *
16259 clutter_margin_copy (const ClutterMargin *margin_)
16260 {
16261   if (G_LIKELY (margin_ != NULL))
16262     return g_slice_dup (ClutterMargin, margin_);
16263
16264   return NULL;
16265 }
16266
16267 /**
16268  * clutter_margin_free:
16269  * @margin_: a #ClutterMargin
16270  *
16271  * Frees the resources allocated by clutter_margin_new() and
16272  * clutter_margin_copy().
16273  *
16274  * Since: 1.10
16275  */
16276 void
16277 clutter_margin_free (ClutterMargin *margin_)
16278 {
16279   if (G_LIKELY (margin_ != NULL))
16280     g_slice_free (ClutterMargin, margin_);
16281 }
16282
16283 G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
16284                      clutter_margin_copy,
16285                      clutter_margin_free)
16286
16287 /**
16288  * clutter_actor_set_margin:
16289  * @self: a #ClutterActor
16290  * @margin: a #ClutterMargin
16291  *
16292  * Sets all the components of the margin of a #ClutterActor.
16293  *
16294  * Since: 1.10
16295  */
16296 void
16297 clutter_actor_set_margin (ClutterActor        *self,
16298                           const ClutterMargin *margin)
16299 {
16300   ClutterLayoutInfo *info;
16301   gboolean changed;
16302   GObject *obj;
16303
16304   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16305   g_return_if_fail (margin != NULL);
16306
16307   obj = G_OBJECT (self);
16308   changed = FALSE;
16309
16310   g_object_freeze_notify (obj);
16311
16312   info = _clutter_actor_get_layout_info (self);
16313
16314   if (info->margin.top != margin->top)
16315     {
16316       info->margin.top = margin->top;
16317       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_TOP]);
16318       changed = TRUE;
16319     }
16320
16321   if (info->margin.right != margin->right)
16322     {
16323       info->margin.right = margin->right;
16324       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_RIGHT]);
16325       changed = TRUE;
16326     }
16327
16328   if (info->margin.bottom != margin->bottom)
16329     {
16330       info->margin.bottom = margin->bottom;
16331       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_BOTTOM]);
16332       changed = TRUE;
16333     }
16334
16335   if (info->margin.left != margin->left)
16336     {
16337       info->margin.left = margin->left;
16338       g_object_notify_by_pspec (obj, obj_props[PROP_MARGIN_LEFT]);
16339       changed = TRUE;
16340     }
16341
16342   if (changed)
16343     clutter_actor_queue_relayout (self);
16344
16345   g_object_thaw_notify (obj);
16346 }
16347
16348 /**
16349  * clutter_actor_get_margin:
16350  * @self: a #ClutterActor
16351  * @margin: (out caller-allocates): return location for a #ClutterMargin
16352  *
16353  * Retrieves all the components of the margin of a #ClutterActor.
16354  *
16355  * Since: 1.10
16356  */
16357 void
16358 clutter_actor_get_margin (ClutterActor  *self,
16359                           ClutterMargin *margin)
16360 {
16361   const ClutterLayoutInfo *info;
16362
16363   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16364   g_return_if_fail (margin != NULL);
16365
16366   info = _clutter_actor_get_layout_info_or_defaults (self);
16367
16368   *margin = info->margin;
16369 }
16370
16371 /**
16372  * clutter_actor_set_margin_top:
16373  * @self: a #ClutterActor
16374  * @margin: the top margin
16375  *
16376  * Sets the margin from the top of a #ClutterActor.
16377  *
16378  * Since: 1.10
16379  */
16380 void
16381 clutter_actor_set_margin_top (ClutterActor *self,
16382                               gfloat        margin)
16383 {
16384   ClutterLayoutInfo *info;
16385
16386   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16387   g_return_if_fail (margin >= 0.f);
16388
16389   info = _clutter_actor_get_layout_info (self);
16390
16391   if (info->margin.top == margin)
16392     return;
16393
16394   info->margin.top = margin;
16395
16396   clutter_actor_queue_relayout (self);
16397
16398   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_TOP]);
16399 }
16400
16401 /**
16402  * clutter_actor_get_margin_top:
16403  * @self: a #ClutterActor
16404  *
16405  * Retrieves the top margin of a #ClutterActor.
16406  *
16407  * Return value: the top margin
16408  *
16409  * Since: 1.10
16410  */
16411 gfloat
16412 clutter_actor_get_margin_top (ClutterActor *self)
16413 {
16414   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16415
16416   return _clutter_actor_get_layout_info_or_defaults (self)->margin.top;
16417 }
16418
16419 /**
16420  * clutter_actor_set_margin_bottom:
16421  * @self: a #ClutterActor
16422  * @margin: the bottom margin
16423  *
16424  * Sets the margin from the bottom of a #ClutterActor.
16425  *
16426  * Since: 1.10
16427  */
16428 void
16429 clutter_actor_set_margin_bottom (ClutterActor *self,
16430                                  gfloat        margin)
16431 {
16432   ClutterLayoutInfo *info;
16433
16434   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16435   g_return_if_fail (margin >= 0.f);
16436
16437   info = _clutter_actor_get_layout_info (self);
16438
16439   if (info->margin.bottom == margin)
16440     return;
16441
16442   info->margin.bottom = margin;
16443
16444   clutter_actor_queue_relayout (self);
16445
16446   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_BOTTOM]);
16447 }
16448
16449 /**
16450  * clutter_actor_get_margin_bottom:
16451  * @self: a #ClutterActor
16452  *
16453  * Retrieves the bottom margin of a #ClutterActor.
16454  *
16455  * Return value: the bottom margin
16456  *
16457  * Since: 1.10
16458  */
16459 gfloat
16460 clutter_actor_get_margin_bottom (ClutterActor *self)
16461 {
16462   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16463
16464   return _clutter_actor_get_layout_info_or_defaults (self)->margin.bottom;
16465 }
16466
16467 /**
16468  * clutter_actor_set_margin_left:
16469  * @self: a #ClutterActor
16470  * @margin: the left margin
16471  *
16472  * Sets the margin from the left of a #ClutterActor.
16473  *
16474  * Since: 1.10
16475  */
16476 void
16477 clutter_actor_set_margin_left (ClutterActor *self,
16478                                gfloat        margin)
16479 {
16480   ClutterLayoutInfo *info;
16481
16482   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16483   g_return_if_fail (margin >= 0.f);
16484
16485   info = _clutter_actor_get_layout_info (self);
16486
16487   if (info->margin.left == margin)
16488     return;
16489
16490   info->margin.left = margin;
16491
16492   clutter_actor_queue_relayout (self);
16493
16494   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_LEFT]);
16495 }
16496
16497 /**
16498  * clutter_actor_get_margin_left:
16499  * @self: a #ClutterActor
16500  *
16501  * Retrieves the left margin of a #ClutterActor.
16502  *
16503  * Return value: the left margin
16504  *
16505  * Since: 1.10
16506  */
16507 gfloat
16508 clutter_actor_get_margin_left (ClutterActor *self)
16509 {
16510   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16511
16512   return _clutter_actor_get_layout_info_or_defaults (self)->margin.left;
16513 }
16514
16515 /**
16516  * clutter_actor_set_margin_right:
16517  * @self: a #ClutterActor
16518  * @margin: the right margin
16519  *
16520  * Sets the margin from the right of a #ClutterActor.
16521  *
16522  * Since: 1.10
16523  */
16524 void
16525 clutter_actor_set_margin_right (ClutterActor *self,
16526                                 gfloat        margin)
16527 {
16528   ClutterLayoutInfo *info;
16529
16530   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16531   g_return_if_fail (margin >= 0.f);
16532
16533   info = _clutter_actor_get_layout_info (self);
16534
16535   if (info->margin.right == margin)
16536     return;
16537
16538   info->margin.right = margin;
16539
16540   clutter_actor_queue_relayout (self);
16541
16542   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MARGIN_RIGHT]);
16543 }
16544
16545 /**
16546  * clutter_actor_get_margin_right:
16547  * @self: a #ClutterActor
16548  *
16549  * Retrieves the right margin of a #ClutterActor.
16550  *
16551  * Return value: the right margin
16552  *
16553  * Since: 1.10
16554  */
16555 gfloat
16556 clutter_actor_get_margin_right (ClutterActor *self)
16557 {
16558   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.f);
16559
16560   return _clutter_actor_get_layout_info_or_defaults (self)->margin.right;
16561 }
16562
16563 static inline void
16564 clutter_actor_set_background_color_internal (ClutterActor *self,
16565                                              const ClutterColor *color)
16566 {
16567   ClutterActorPrivate *priv = self->priv;
16568   GObject *obj;
16569
16570   if (priv->bg_color_set && clutter_color_equal (color, &priv->bg_color))
16571     return;
16572
16573   obj = G_OBJECT (self);
16574
16575   priv->bg_color = *color;
16576   priv->bg_color_set = TRUE;
16577
16578   clutter_actor_queue_redraw (self);
16579
16580   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16581   g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR]);
16582 }
16583
16584 /**
16585  * clutter_actor_set_background_color:
16586  * @self: a #ClutterActor
16587  * @color: (allow-none): a #ClutterColor, or %NULL to unset a previously
16588  *  set color
16589  *
16590  * Sets the background color of a #ClutterActor.
16591  *
16592  * The background color will be used to cover the whole allocation of the
16593  * actor. The default background color of an actor is transparent.
16594  *
16595  * To check whether an actor has a background color, you can use the
16596  * #ClutterActor:background-color-set actor property.
16597  *
16598  * The #ClutterActor:background-color property is animatable.
16599  *
16600  * Since: 1.10
16601  */
16602 void
16603 clutter_actor_set_background_color (ClutterActor       *self,
16604                                     const ClutterColor *color)
16605 {
16606   ClutterActorPrivate *priv;
16607   GObject *obj;
16608   GParamSpec *bg_color_pspec;
16609
16610   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16611
16612   obj = G_OBJECT (self);
16613
16614   priv = self->priv;
16615
16616   if (color == NULL)
16617     {
16618       priv->bg_color_set = FALSE;
16619       g_object_notify_by_pspec (obj, obj_props[PROP_BACKGROUND_COLOR_SET]);
16620       clutter_actor_queue_redraw (self);
16621       return;
16622     }
16623
16624   bg_color_pspec = obj_props[PROP_BACKGROUND_COLOR];
16625   if (_clutter_actor_get_transition (self, bg_color_pspec) == NULL)
16626     {
16627       _clutter_actor_create_transition (self, bg_color_pspec,
16628                                         &priv->bg_color,
16629                                         color);
16630     }
16631   else
16632     _clutter_actor_update_transition (self, bg_color_pspec, color);
16633
16634   clutter_actor_queue_redraw (self);
16635 }
16636
16637 /**
16638  * clutter_actor_get_background_color:
16639  * @self: a #ClutterActor
16640  * @color: (out caller-allocates): return location for a #ClutterColor
16641  *
16642  * Retrieves the color set using clutter_actor_set_background_color().
16643  *
16644  * Since: 1.10
16645  */
16646 void
16647 clutter_actor_get_background_color (ClutterActor *self,
16648                                     ClutterColor *color)
16649 {
16650   g_return_if_fail (CLUTTER_IS_ACTOR (self));
16651   g_return_if_fail (color != NULL);
16652
16653   *color = self->priv->bg_color;
16654 }
16655
16656 /**
16657  * clutter_actor_get_previous_sibling:
16658  * @self: a #ClutterActor
16659  *
16660  * Retrieves the sibling of @self that comes before it in the list
16661  * of children of @self's parent.
16662  *
16663  * The returned pointer is only valid until the scene graph changes; it
16664  * is not safe to modify the list of children of @self while iterating
16665  * it.
16666  *
16667  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16668  *
16669  * Since: 1.10
16670  */
16671 ClutterActor *
16672 clutter_actor_get_previous_sibling (ClutterActor *self)
16673 {
16674   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16675
16676   return self->priv->prev_sibling;
16677 }
16678
16679 /**
16680  * clutter_actor_get_next_sibling:
16681  * @self: a #ClutterActor
16682  *
16683  * Retrieves the sibling of @self that comes after it in the list
16684  * of children of @self's parent.
16685  *
16686  * The returned pointer is only valid until the scene graph changes; it
16687  * is not safe to modify the list of children of @self while iterating
16688  * it.
16689  *
16690  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16691  *
16692  * Since: 1.10
16693  */
16694 ClutterActor *
16695 clutter_actor_get_next_sibling (ClutterActor *self)
16696 {
16697   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16698
16699   return self->priv->next_sibling;
16700 }
16701
16702 /**
16703  * clutter_actor_get_first_child:
16704  * @self: a #ClutterActor
16705  *
16706  * Retrieves the first child of @self.
16707  *
16708  * The returned pointer is only valid until the scene graph changes; it
16709  * is not safe to modify the list of children of @self while iterating
16710  * it.
16711  *
16712  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16713  *
16714  * Since: 1.10
16715  */
16716 ClutterActor *
16717 clutter_actor_get_first_child (ClutterActor *self)
16718 {
16719   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16720
16721   return self->priv->first_child;
16722 }
16723
16724 /**
16725  * clutter_actor_get_last_child:
16726  * @self: a #ClutterActor
16727  *
16728  * Retrieves the last child of @self.
16729  *
16730  * The returned pointer is only valid until the scene graph changes; it
16731  * is not safe to modify the list of children of @self while iterating
16732  * it.
16733  *
16734  * Return value: (transfer none): a pointer to a #ClutterActor, or %NULL
16735  *
16736  * Since: 1.10
16737  */
16738 ClutterActor *
16739 clutter_actor_get_last_child (ClutterActor *self)
16740 {
16741   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
16742
16743   return self->priv->last_child;
16744 }
16745
16746 /* easy way to have properly named fields instead of the dummy ones
16747  * we use in the public structure
16748  */
16749 typedef struct _RealActorIter
16750 {
16751   ClutterActor *root;           /* dummy1 */
16752   ClutterActor *current;        /* dummy2 */
16753   gpointer padding_1;           /* dummy3 */
16754   gint age;                     /* dummy4 */
16755   gpointer padding_2;           /* dummy5 */
16756 } RealActorIter;
16757
16758 /**
16759  * clutter_actor_iter_init:
16760  * @iter: a #ClutterActorIter
16761  * @root: a #ClutterActor
16762  *
16763  * Initializes a #ClutterActorIter, which can then be used to iterate
16764  * efficiently over a section of the scene graph, and associates it
16765  * with @root.
16766  *
16767  * Modifying the scene graph section that contains @root will invalidate
16768  * the iterator.
16769  *
16770  * |[
16771  *   ClutterActorIter iter;
16772  *   ClutterActor *child;
16773  *
16774  *   clutter_actor_iter_init (&iter, container);
16775  *   while (clutter_actor_iter_next (&iter, &child))
16776  *     {
16777  *       /&ast; do something with child &ast;/
16778  *     }
16779  * ]|
16780  *
16781  * Since: 1.10
16782  */
16783 void
16784 clutter_actor_iter_init (ClutterActorIter *iter,
16785                          ClutterActor     *root)
16786 {
16787   RealActorIter *ri = (RealActorIter *) iter;
16788
16789   g_return_if_fail (iter != NULL);
16790   g_return_if_fail (CLUTTER_IS_ACTOR (root));
16791
16792   ri->root = root;
16793   ri->current = NULL;
16794   ri->age = root->priv->age;
16795 }
16796
16797 /**
16798  * clutter_actor_iter_next:
16799  * @iter: a #ClutterActorIter
16800  * @child: (out): return location for a #ClutterActor
16801  *
16802  * Advances the @iter and retrieves the next child of the root #ClutterActor
16803  * that was used to initialize the #ClutterActorIterator.
16804  *
16805  * If the iterator can advance, this function returns %TRUE and sets the
16806  * @child argument.
16807  *
16808  * If the iterator cannot advance, this function returns %FALSE, and
16809  * the contents of @child are undefined.
16810  *
16811  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16812  *
16813  * Since: 1.10
16814  */
16815 gboolean
16816 clutter_actor_iter_next (ClutterActorIter  *iter,
16817                          ClutterActor     **child)
16818 {
16819   RealActorIter *ri = (RealActorIter *) iter;
16820
16821   g_return_val_if_fail (iter != NULL, FALSE);
16822   g_return_val_if_fail (ri->root != NULL, FALSE);
16823 #ifndef G_DISABLE_ASSERT
16824   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16825 #endif
16826
16827   if (ri->current == NULL)
16828     ri->current = ri->root->priv->first_child;
16829   else
16830     ri->current = ri->current->priv->next_sibling;
16831
16832   if (child != NULL)
16833     *child = ri->current;
16834
16835   return ri->current != NULL;
16836 }
16837
16838 /**
16839  * clutter_actor_iter_prev:
16840  * @iter: a #ClutterActorIter
16841  * @child: (out): return location for a #ClutterActor
16842  *
16843  * Advances the @iter and retrieves the previous child of the root
16844  * #ClutterActor that was used to initialize the #ClutterActorIterator.
16845  *
16846  * If the iterator can advance, this function returns %TRUE and sets the
16847  * @child argument.
16848  *
16849  * If the iterator cannot advance, this function returns %FALSE, and
16850  * the contents of @child are undefined.
16851  *
16852  * Return value: %TRUE if the iterator could advance, and %FALSE otherwise.
16853  *
16854  * Since: 1.10
16855  */
16856 gboolean
16857 clutter_actor_iter_prev (ClutterActorIter  *iter,
16858                          ClutterActor     **child)
16859 {
16860   RealActorIter *ri = (RealActorIter *) iter;
16861
16862   g_return_val_if_fail (iter != NULL, FALSE);
16863   g_return_val_if_fail (ri->root != NULL, FALSE);
16864 #ifndef G_DISABLE_ASSERT
16865   g_return_val_if_fail (ri->age == ri->root->priv->age, FALSE);
16866 #endif
16867
16868   if (ri->current == NULL)
16869     ri->current = ri->root->priv->last_child;
16870   else
16871     ri->current = ri->current->priv->prev_sibling;
16872
16873   if (child != NULL)
16874     *child = ri->current;
16875
16876   return ri->current != NULL;
16877 }
16878
16879 /**
16880  * clutter_actor_iter_remove:
16881  * @iter: a #ClutterActorIter
16882  *
16883  * Safely removes the #ClutterActor currently pointer to by the iterator
16884  * from its parent.
16885  *
16886  * This function can only be called after clutter_actor_iter_next() or
16887  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16888  * than once for the same actor.
16889  *
16890  * This function will call clutter_actor_remove_child() internally.
16891  *
16892  * Since: 1.10
16893  */
16894 void
16895 clutter_actor_iter_remove (ClutterActorIter *iter)
16896 {
16897   RealActorIter *ri = (RealActorIter *) iter;
16898   ClutterActor *cur;
16899
16900   g_return_if_fail (iter != NULL);
16901   g_return_if_fail (ri->root != NULL);
16902 #ifndef G_DISABLE_ASSERT
16903   g_return_if_fail (ri->age == ri->root->priv->age);
16904 #endif
16905   g_return_if_fail (ri->current != NULL);
16906
16907   cur = ri->current;
16908
16909   if (cur != NULL)
16910     {
16911       ri->current = cur->priv->prev_sibling;
16912
16913       clutter_actor_remove_child_internal (ri->root, cur,
16914                                            REMOVE_CHILD_DEFAULT_FLAGS);
16915
16916       ri->age += 1;
16917     }
16918 }
16919
16920 /**
16921  * clutter_actor_iter_destroy:
16922  * @iter: a #ClutterActorIter
16923  *
16924  * Safely destroys the #ClutterActor currently pointer to by the iterator
16925  * from its parent.
16926  *
16927  * This function can only be called after clutter_actor_iter_next() or
16928  * clutter_actor_iter_prev() returned %TRUE, and cannot be called more
16929  * than once for the same actor.
16930  *
16931  * This function will call clutter_actor_destroy() internally.
16932  *
16933  * Since: 1.10
16934  */
16935 void
16936 clutter_actor_iter_destroy (ClutterActorIter *iter)
16937 {
16938   RealActorIter *ri = (RealActorIter *) iter;
16939   ClutterActor *cur;
16940
16941   g_return_if_fail (iter != NULL);
16942   g_return_if_fail (ri->root != NULL);
16943 #ifndef G_DISABLE_ASSERT
16944   g_return_if_fail (ri->age == ri->root->priv->age);
16945 #endif
16946   g_return_if_fail (ri->current != NULL);
16947
16948   cur = ri->current;
16949
16950   if (cur != NULL)
16951     {
16952       ri->current = cur->priv->prev_sibling;
16953
16954       clutter_actor_destroy (cur);
16955
16956       ri->age += 1;
16957     }
16958 }
16959
16960 static const ClutterAnimationInfo default_animation_info = {
16961   NULL,         /* transitions */
16962   NULL,         /* states */
16963   NULL,         /* cur_state */
16964 };
16965
16966 static void
16967 clutter_animation_info_free (gpointer data)
16968 {
16969   if (data != NULL)
16970     {
16971       ClutterAnimationInfo *info = data;
16972
16973       if (info->transitions != NULL)
16974         g_hash_table_unref (info->transitions);
16975
16976       if (info->states != NULL)
16977         g_array_unref (info->states);
16978
16979       g_slice_free (ClutterAnimationInfo, info);
16980     }
16981 }
16982
16983 const ClutterAnimationInfo *
16984 _clutter_actor_get_animation_info_or_defaults (ClutterActor *self)
16985 {
16986   const ClutterAnimationInfo *res;
16987   GObject *obj = G_OBJECT (self);
16988
16989   res = g_object_get_qdata (obj, quark_actor_animation_info);
16990   if (res != NULL)
16991     return res;
16992
16993   return &default_animation_info;
16994 }
16995
16996 ClutterAnimationInfo *
16997 _clutter_actor_get_animation_info (ClutterActor *self)
16998 {
16999   GObject *obj = G_OBJECT (self);
17000   ClutterAnimationInfo *res;
17001
17002   res = g_object_get_qdata (obj, quark_actor_animation_info);
17003   if (res == NULL)
17004     {
17005       res = g_slice_new (ClutterAnimationInfo);
17006
17007       *res = default_animation_info;
17008
17009       g_object_set_qdata_full (obj, quark_actor_animation_info,
17010                                res,
17011                                clutter_animation_info_free);
17012     }
17013
17014   return res;
17015 }
17016
17017 ClutterTransition *
17018 _clutter_actor_get_transition (ClutterActor *actor,
17019                                GParamSpec   *pspec)
17020 {
17021   const ClutterAnimationInfo *info;
17022
17023   info = _clutter_actor_get_animation_info_or_defaults (actor);
17024
17025   if (info->transitions == NULL)
17026     return NULL;
17027
17028   return g_hash_table_lookup (info->transitions, pspec->name);
17029 }
17030
17031 typedef struct _TransitionClosure
17032 {
17033   ClutterActor *actor;
17034   ClutterTransition *transition;
17035   gchar *name;
17036   gulong completed_id;
17037 } TransitionClosure;
17038
17039 static void
17040 transition_closure_free (gpointer data)
17041 {
17042   if (G_LIKELY (data != NULL))
17043     {
17044       TransitionClosure *clos = data;
17045       ClutterTimeline *timeline;
17046
17047       timeline = CLUTTER_TIMELINE (clos->transition);
17048
17049       if (clutter_timeline_is_playing (timeline))
17050         clutter_timeline_stop (timeline);
17051
17052       g_signal_handler_disconnect (clos->transition, clos->completed_id);
17053
17054       g_object_unref (clos->transition);
17055       g_free (clos->name);
17056
17057       g_slice_free (TransitionClosure, clos);
17058     }
17059 }
17060
17061 static void
17062 on_transition_completed (ClutterTransition *transition,
17063                          TransitionClosure *clos)
17064 {
17065   ClutterActor *actor = clos->actor;
17066   ClutterAnimationInfo *info;
17067
17068   /* reset the caches used by animations */
17069   clutter_actor_store_content_box (actor, NULL);
17070
17071   info = _clutter_actor_get_animation_info (actor);
17072
17073   /* this will take care of cleaning clos for us */
17074   if (!clutter_transition_get_remove_on_complete (transition))
17075     {
17076       /* we take a reference here because removing the closure
17077        * will release the reference on the transition, and we
17078        * want the transition to survive the signal emission;
17079        * the master clock will release the laste reference at
17080        * the end of the frame processing.
17081        */
17082       g_object_ref (transition);
17083       g_hash_table_remove (info->transitions, clos->name);
17084     }
17085   else
17086     {
17087       ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
17088       gint n_repeats, cur_repeat;
17089
17090       /* ensure that we remove the transition only at the end
17091        * of its run; we emit ::completed for every repeat
17092        */
17093
17094       n_repeats = clutter_timeline_get_repeat_count (timeline);
17095       cur_repeat = clutter_timeline_get_current_repeat (timeline);
17096
17097       if (cur_repeat == n_repeats)
17098         {
17099           /* see the comment above on why this ref() is necessary */
17100           g_object_ref (transition);
17101           g_hash_table_remove (info->transitions, clos->name);
17102         }
17103     }
17104
17105   /* if it's the last transition then we clean up */
17106   if (g_hash_table_size (info->transitions) == 0)
17107     {
17108       g_hash_table_unref (info->transitions);
17109       info->transitions = NULL;
17110
17111       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17112                     _clutter_actor_get_debug_name (actor));
17113
17114       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17115     }
17116 }
17117
17118 void
17119 _clutter_actor_update_transition (ClutterActor *actor,
17120                                   GParamSpec   *pspec,
17121                                   ...)
17122 {
17123   TransitionClosure *clos;
17124   ClutterTimeline *timeline;
17125   ClutterInterval *interval;
17126   const ClutterAnimationInfo *info;
17127   va_list var_args;
17128   GType ptype;
17129   GValue initial = G_VALUE_INIT;
17130   GValue final = G_VALUE_INIT;
17131   char *error = NULL;
17132
17133   info = _clutter_actor_get_animation_info_or_defaults (actor);
17134
17135   if (info->transitions == NULL)
17136     return;
17137
17138   clos = g_hash_table_lookup (info->transitions, pspec->name);
17139   if (clos == NULL)
17140     return;
17141
17142   timeline = CLUTTER_TIMELINE (clos->transition);
17143
17144   va_start (var_args, pspec);
17145
17146   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17147
17148   g_value_init (&initial, ptype);
17149   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17150                                         pspec->name,
17151                                         &initial);
17152
17153   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17154   if (error != NULL)
17155     {
17156       g_critical ("%s: %s", G_STRLOC, error);
17157       g_free (error);
17158       goto out;
17159     }
17160
17161   interval = clutter_transition_get_interval (clos->transition);
17162   clutter_interval_set_initial_value (interval, &initial);
17163   clutter_interval_set_final_value (interval, &final);
17164
17165   /* if we're updating with an easing duration of zero milliseconds,
17166    * we just jump the timeline to the end and let it run its course
17167    */
17168   if (info->cur_state != NULL &&
17169       info->cur_state->easing_duration != 0)
17170     {
17171       guint cur_duration = clutter_timeline_get_duration (timeline);
17172       ClutterAnimationMode cur_mode =
17173         clutter_timeline_get_progress_mode (timeline);
17174
17175       if (cur_duration != info->cur_state->easing_duration)
17176         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17177
17178       if (cur_mode != info->cur_state->easing_mode)
17179         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17180
17181       clutter_timeline_rewind (timeline);
17182     }
17183   else
17184     {
17185       guint duration = clutter_timeline_get_duration (timeline);
17186
17187       clutter_timeline_advance (timeline, duration);
17188     }
17189
17190 out:
17191   g_value_unset (&initial);
17192   g_value_unset (&final);
17193
17194   va_end (var_args);
17195 }
17196
17197 /*< private >*
17198  * _clutter_actor_create_transition:
17199  * @actor: a #ClutterActor
17200  * @pspec: the property used for the transition
17201  * @...: initial and final state
17202  *
17203  * Creates a #ClutterTransition for the property represented by @pspec.
17204  *
17205  * Return value: a #ClutterTransition
17206  */
17207 ClutterTransition *
17208 _clutter_actor_create_transition (ClutterActor *actor,
17209                                   GParamSpec   *pspec,
17210                                   ...)
17211 {
17212   ClutterAnimationInfo *info;
17213   ClutterTransition *res = NULL;
17214   gboolean call_restore = FALSE;
17215   TransitionClosure *clos;
17216   va_list var_args;
17217
17218   info = _clutter_actor_get_animation_info (actor);
17219
17220   /* XXX - this will go away in 2.0
17221    *
17222    * if no state has been pushed, we assume that the easing state is
17223    * in "compatibility mode": all transitions have a duration of 0
17224    * msecs, which means that they happen immediately. in Clutter 2.0
17225    * this will turn into a g_assert(info->states != NULL), as every
17226    * actor will start with a predefined easing state
17227    */
17228   if (info->states == NULL)
17229     {
17230       clutter_actor_save_easing_state (actor);
17231       clutter_actor_set_easing_duration (actor, 0);
17232       call_restore = TRUE;
17233     }
17234
17235   if (info->transitions == NULL)
17236     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17237                                                NULL,
17238                                                transition_closure_free);
17239
17240   va_start (var_args, pspec);
17241
17242   clos = g_hash_table_lookup (info->transitions, pspec->name);
17243   if (clos == NULL)
17244     {
17245       ClutterInterval *interval;
17246       GValue initial = G_VALUE_INIT;
17247       GValue final = G_VALUE_INIT;
17248       GType ptype;
17249       char *error;
17250
17251       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17252
17253       G_VALUE_COLLECT_INIT (&initial, ptype,
17254                             var_args, 0,
17255                             &error);
17256       if (error != NULL)
17257         {
17258           g_critical ("%s: %s", G_STRLOC, error);
17259           g_free (error);
17260           goto out;
17261         }
17262
17263       G_VALUE_COLLECT_INIT (&final, ptype,
17264                             var_args, 0,
17265                             &error);
17266
17267       if (error != NULL)
17268         {
17269           g_critical ("%s: %s", G_STRLOC, error);
17270           g_value_unset (&initial);
17271           g_free (error);
17272           goto out;
17273         }
17274
17275       /* if the current easing state has a duration of 0, then we don't
17276        * bother to create the transition, and we just set the final value
17277        * directly on the actor; we don't go through the Animatable
17278        * interface because we know we got here through an animatable
17279        * property.
17280        */
17281       if (info->cur_state->easing_duration == 0)
17282         {
17283           clutter_actor_set_animatable_property (actor,
17284                                                  pspec->param_id,
17285                                                  &final,
17286                                                  pspec);
17287           g_value_unset (&initial);
17288           g_value_unset (&final);
17289
17290           goto out;
17291         }
17292
17293       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17294
17295       g_value_unset (&initial);
17296       g_value_unset (&final);
17297
17298       res = clutter_property_transition_new (pspec->name);
17299
17300       clutter_transition_set_interval (res, interval);
17301       clutter_transition_set_remove_on_complete (res, TRUE);
17302
17303       /* this will start the transition as well */
17304       clutter_actor_add_transition (actor, pspec->name, res);
17305
17306       /* the actor now owns the transition */
17307       g_object_unref (res);
17308     }
17309   else
17310     res = clos->transition;
17311
17312 out:
17313   if (call_restore)
17314     clutter_actor_restore_easing_state (actor);
17315
17316   va_end (var_args);
17317
17318   return res;
17319 }
17320
17321 /**
17322  * clutter_actor_add_transition:
17323  * @self: a #ClutterActor
17324  * @name: the name of the transition to add
17325  * @transition: the #ClutterTransition to add
17326  *
17327  * Adds a @transition to the #ClutterActor's list of animations.
17328  *
17329  * The @name string is a per-actor unique identifier of the @transition: only
17330  * one #ClutterTransition can be associated to the specified @name.
17331  *
17332  * The @transition will be given the easing duration, mode, and delay
17333  * associated to the actor's current easing state; it is possible to modify
17334  * these values after calling clutter_actor_add_transition().
17335  *
17336  * The @transition will be started once added.
17337  *
17338  * This function will take a reference on the @transition.
17339  *
17340  * This function is usually called implicitly when modifying an animatable
17341  * property.
17342  *
17343  * Since: 1.10
17344  */
17345 void
17346 clutter_actor_add_transition (ClutterActor      *self,
17347                               const char        *name,
17348                               ClutterTransition *transition)
17349 {
17350   ClutterTimeline *timeline;
17351   TransitionClosure *clos;
17352   ClutterAnimationInfo *info;
17353
17354   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17355   g_return_if_fail (name != NULL);
17356   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17357
17358   info = _clutter_actor_get_animation_info (self);
17359
17360   if (info->cur_state == NULL)
17361     {
17362       g_warning ("No easing state is defined for the actor '%s'; you "
17363                  "must call clutter_actor_save_easing_state() before "
17364                  "calling clutter_actor_add_transition().",
17365                  _clutter_actor_get_debug_name (self));
17366       return;
17367     }
17368
17369   if (info->transitions == NULL)
17370     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17371                                                NULL,
17372                                                transition_closure_free);
17373
17374   if (g_hash_table_lookup (info->transitions, name) != NULL)
17375     {
17376       g_warning ("A transition with name '%s' already exists for "
17377                  "the actor '%s'",
17378                  name,
17379                  _clutter_actor_get_debug_name (self));
17380       return;
17381     }
17382
17383   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17384
17385   timeline = CLUTTER_TIMELINE (transition);
17386
17387   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17388   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17389   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17390
17391   clos = g_slice_new (TransitionClosure);
17392   clos->actor = self;
17393   clos->transition = g_object_ref (transition);
17394   clos->name = g_strdup (name);
17395   clos->completed_id = g_signal_connect (timeline, "completed",
17396                                          G_CALLBACK (on_transition_completed),
17397                                          clos);
17398
17399   CLUTTER_NOTE (ANIMATION,
17400                 "Adding transition '%s' [%p] to actor '%s'",
17401                 clos->name,
17402                 clos->transition,
17403                 _clutter_actor_get_debug_name (self));
17404
17405   g_hash_table_insert (info->transitions, clos->name, clos);
17406   clutter_timeline_start (timeline);
17407 }
17408
17409 /**
17410  * clutter_actor_remove_transition:
17411  * @self: a #ClutterActor
17412  * @name: the name of the transition to remove
17413  *
17414  * Removes the transition stored inside a #ClutterActor using @name
17415  * identifier.
17416  *
17417  * If the transition is currently in progress, it will be stopped.
17418  *
17419  * This function releases the reference acquired when the transition
17420  * was added to the #ClutterActor.
17421  *
17422  * Since: 1.10
17423  */
17424 void
17425 clutter_actor_remove_transition (ClutterActor *self,
17426                                  const char   *name)
17427 {
17428   const ClutterAnimationInfo *info;
17429
17430   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17431   g_return_if_fail (name != NULL);
17432
17433   info = _clutter_actor_get_animation_info_or_defaults (self);
17434
17435   if (info->transitions == NULL)
17436     return;
17437
17438   g_hash_table_remove (info->transitions, name);
17439 }
17440
17441 /**
17442  * clutter_actor_remove_all_transitions:
17443  * @self: a #ClutterActor
17444  *
17445  * Removes all transitions associated to @self.
17446  *
17447  * Since: 1.10
17448  */
17449 void
17450 clutter_actor_remove_all_transitions (ClutterActor *self)
17451 {
17452   const ClutterAnimationInfo *info;
17453
17454   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17455
17456   info = _clutter_actor_get_animation_info_or_defaults (self);
17457   if (info->transitions == NULL)
17458     return;
17459
17460   g_hash_table_remove_all (info->transitions);
17461 }
17462
17463 /**
17464  * clutter_actor_set_easing_duration:
17465  * @self: a #ClutterActor
17466  * @msecs: the duration of the easing, or %NULL
17467  *
17468  * Sets the duration of the tweening for animatable properties
17469  * of @self for the current easing state.
17470  *
17471  * Since: 1.10
17472  */
17473 void
17474 clutter_actor_set_easing_duration (ClutterActor *self,
17475                                    guint         msecs)
17476 {
17477   ClutterAnimationInfo *info;
17478
17479   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17480
17481   info = _clutter_actor_get_animation_info (self);
17482
17483   if (info->cur_state == NULL)
17484     {
17485       g_warning ("You must call clutter_actor_save_easing_state() prior "
17486                  "to calling clutter_actor_set_easing_duration().");
17487       return;
17488     }
17489
17490   if (info->cur_state->easing_duration != msecs)
17491     info->cur_state->easing_duration = msecs;
17492 }
17493
17494 /**
17495  * clutter_actor_get_easing_duration:
17496  * @self: a #ClutterActor
17497  *
17498  * Retrieves the duration of the tweening for animatable
17499  * properties of @self for the current easing state.
17500  *
17501  * Return value: the duration of the tweening, in milliseconds
17502  *
17503  * Since: 1.10
17504  */
17505 guint
17506 clutter_actor_get_easing_duration (ClutterActor *self)
17507 {
17508   const ClutterAnimationInfo *info;
17509
17510   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17511
17512   info = _clutter_actor_get_animation_info_or_defaults (self);
17513
17514   if (info->cur_state != NULL)
17515     return info->cur_state->easing_duration;
17516
17517   return 0;
17518 }
17519
17520 /**
17521  * clutter_actor_set_easing_mode:
17522  * @self: a #ClutterActor
17523  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17524  *
17525  * Sets the easing mode for the tweening of animatable properties
17526  * of @self.
17527  *
17528  * Since: 1.10
17529  */
17530 void
17531 clutter_actor_set_easing_mode (ClutterActor         *self,
17532                                ClutterAnimationMode  mode)
17533 {
17534   ClutterAnimationInfo *info;
17535
17536   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17537   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17538   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17539
17540   info = _clutter_actor_get_animation_info (self);
17541
17542   if (info->cur_state == NULL)
17543     {
17544       g_warning ("You must call clutter_actor_save_easing_state() prior "
17545                  "to calling clutter_actor_set_easing_mode().");
17546       return;
17547     }
17548
17549   if (info->cur_state->easing_mode != mode)
17550     info->cur_state->easing_mode = mode;
17551 }
17552
17553 /**
17554  * clutter_actor_get_easing_mode:
17555  * @self: a #ClutterActor
17556  *
17557  * Retrieves the easing mode for the tweening of animatable properties
17558  * of @self for the current easing state.
17559  *
17560  * Return value: an easing mode
17561  *
17562  * Since: 1.10
17563  */
17564 ClutterAnimationMode
17565 clutter_actor_get_easing_mode (ClutterActor *self)
17566 {
17567   const ClutterAnimationInfo *info;
17568
17569   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17570
17571   info = _clutter_actor_get_animation_info_or_defaults (self);
17572
17573   if (info->cur_state != NULL)
17574     return info->cur_state->easing_mode;
17575
17576   return CLUTTER_EASE_OUT_CUBIC;
17577 }
17578
17579 /**
17580  * clutter_actor_set_easing_delay:
17581  * @self: a #ClutterActor
17582  * @msecs: the delay before the start of the tweening, in milliseconds
17583  *
17584  * Sets the delay that should be applied before tweening animatable
17585  * properties.
17586  *
17587  * Since: 1.10
17588  */
17589 void
17590 clutter_actor_set_easing_delay (ClutterActor *self,
17591                                 guint         msecs)
17592 {
17593   ClutterAnimationInfo *info;
17594
17595   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17596
17597   info = _clutter_actor_get_animation_info (self);
17598
17599   if (info->cur_state == NULL)
17600     {
17601       g_warning ("You must call clutter_actor_save_easing_state() prior "
17602                  "to calling clutter_actor_set_easing_delay().");
17603       return;
17604     }
17605
17606   if (info->cur_state->easing_delay != msecs)
17607     info->cur_state->easing_delay = msecs;
17608 }
17609
17610 /**
17611  * clutter_actor_get_easing_delay:
17612  * @self: a #ClutterActor
17613  *
17614  * Retrieves the delay that should be applied when tweening animatable
17615  * properties.
17616  *
17617  * Return value: a delay, in milliseconds
17618  *
17619  * Since: 1.10
17620  */
17621 guint
17622 clutter_actor_get_easing_delay (ClutterActor *self)
17623 {
17624   const ClutterAnimationInfo *info;
17625
17626   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17627
17628   info = _clutter_actor_get_animation_info_or_defaults (self);
17629
17630   if (info->cur_state != NULL)
17631     return info->cur_state->easing_delay;
17632
17633   return 0;
17634 }
17635
17636 /**
17637  * clutter_actor_get_transition:
17638  * @self: a #ClutterActor
17639  * @name: the name of the transition
17640  *
17641  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17642  * transition @name.
17643  *
17644  * Transitions created for animatable properties use the name of the
17645  * property itself, for instance the code below:
17646  *
17647  * |[
17648  *   clutter_actor_set_easing_duration (actor, 1000);
17649  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17650  *
17651  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17652  *   g_signal_connect (transition, "completed",
17653  *                     G_CALLBACK (on_transition_complete),
17654  *                     actor);
17655  * ]|
17656  *
17657  * will call the <function>on_transition_complete</function> callback when
17658  * the transition is complete.
17659  *
17660  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17661  *   was found to match the passed name; the returned instance is owned
17662  *   by Clutter and it should not be freed
17663  *
17664  * Since: 1.10
17665  */
17666 ClutterTransition *
17667 clutter_actor_get_transition (ClutterActor *self,
17668                               const char   *name)
17669 {
17670   TransitionClosure *clos;
17671   const ClutterAnimationInfo *info;
17672
17673   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17674   g_return_val_if_fail (name != NULL, NULL);
17675
17676   info = _clutter_actor_get_animation_info_or_defaults (self);
17677   if (info->transitions == NULL)
17678     return NULL;
17679
17680   clos = g_hash_table_lookup (info->transitions, name);
17681   if (clos == NULL)
17682     return NULL;
17683
17684   return clos->transition;
17685 }
17686
17687 /**
17688  * clutter_actor_save_easing_state:
17689  * @self: a #ClutterActor
17690  *
17691  * Saves the current easing state for animatable properties, and creates
17692  * a new state with the default values for easing mode and duration.
17693  *
17694  * Since: 1.10
17695  */
17696 void
17697 clutter_actor_save_easing_state (ClutterActor *self)
17698 {
17699   ClutterAnimationInfo *info;
17700   AState new_state;
17701
17702   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17703
17704   info = _clutter_actor_get_animation_info (self);
17705
17706   if (info->states == NULL)
17707     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17708
17709   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17710   new_state.easing_duration = 250;
17711   new_state.easing_delay = 0;
17712
17713   g_array_append_val (info->states, new_state);
17714
17715   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17716 }
17717
17718 /**
17719  * clutter_actor_restore_easing_state:
17720  * @self: a #ClutterActor
17721  *
17722  * Restores the easing state as it was prior to a call to
17723  * clutter_actor_save_easing_state().
17724  *
17725  * Since: 1.10
17726  */
17727 void
17728 clutter_actor_restore_easing_state (ClutterActor *self)
17729 {
17730   ClutterAnimationInfo *info;
17731
17732   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17733
17734   info = _clutter_actor_get_animation_info (self);
17735
17736   if (info->states == NULL)
17737     {
17738       g_critical ("The function clutter_actor_restore_easing_state() has "
17739                   "called without a previous call to "
17740                   "clutter_actor_save_easing_state().");
17741       return;
17742     }
17743
17744   g_array_remove_index (info->states, info->states->len - 1);
17745
17746   if (info->states->len > 0)
17747     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17748   else
17749     {
17750       g_array_unref (info->states);
17751       info->states = NULL;
17752       info->cur_state = NULL;
17753     }
17754 }
17755
17756 /**
17757  * clutter_actor_set_content:
17758  * @self: a #ClutterActor
17759  * @content: (allow-none): a #ClutterContent, or %NULL
17760  *
17761  * Sets the contents of a #ClutterActor.
17762  *
17763  * Since: 1.10
17764  */
17765 void
17766 clutter_actor_set_content (ClutterActor   *self,
17767                            ClutterContent *content)
17768 {
17769   ClutterActorPrivate *priv;
17770
17771   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17772   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17773
17774   priv = self->priv;
17775
17776   if (priv->content != NULL)
17777     {
17778       _clutter_content_detached (priv->content, self);
17779       g_clear_object (&priv->content);
17780     }
17781
17782   priv->content = content;
17783
17784   if (priv->content != NULL)
17785     {
17786       g_object_ref (priv->content);
17787       _clutter_content_attached (priv->content, self);
17788     }
17789
17790   /* given that the content is always painted within the allocation,
17791    * we only need to queue a redraw here
17792    */
17793   clutter_actor_queue_redraw (self);
17794
17795   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17796
17797   /* if the content gravity is not resize-fill, and the new content has a
17798    * different preferred size than the previous one, then the content box
17799    * may have been changed. since we compute that lazily, we just notify
17800    * here, and let whomever watches :content-box do whatever they need to
17801    * do.
17802    */
17803   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17804     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17805 }
17806
17807 /**
17808  * clutter_actor_get_content:
17809  * @self: a #ClutterActor
17810  *
17811  * Retrieves the contents of @self.
17812  *
17813  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17814  *   or %NULL if none was set
17815  *
17816  * Since: 1.10
17817  */
17818 ClutterContent *
17819 clutter_actor_get_content (ClutterActor *self)
17820 {
17821   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17822
17823   return self->priv->content;
17824 }
17825
17826 /**
17827  * clutter_actor_set_content_gravity:
17828  * @self: a #ClutterActor
17829  * @gravity: the #ClutterContentGravity
17830  *
17831  * Sets the gravity of the #ClutterContent used by @self.
17832  *
17833  * See the description of the #ClutterActor:content-gravity property for
17834  * more information.
17835  *
17836  * The #ClutterActor:content-gravity property is animatable.
17837  *
17838  * Since: 1.10
17839  */
17840 void
17841 clutter_actor_set_content_gravity (ClutterActor *self,
17842                                    ClutterContentGravity  gravity)
17843 {
17844   ClutterActorPrivate *priv;
17845
17846   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17847
17848   priv = self->priv;
17849
17850   if (priv->content_gravity == gravity)
17851     return;
17852
17853   priv->content_box_valid = FALSE;
17854
17855   if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17856     {
17857       ClutterActorBox from_box, to_box;
17858
17859       clutter_actor_get_content_box (self, &from_box);
17860
17861       priv->content_gravity = gravity;
17862
17863       clutter_actor_get_content_box (self, &to_box);
17864
17865       _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17866                                         &from_box,
17867                                         &to_box);
17868     }
17869   else
17870     {
17871       ClutterActorBox to_box;
17872
17873       priv->content_gravity = gravity;
17874
17875       clutter_actor_get_content_box (self, &to_box);
17876
17877       _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17878                                         &to_box);
17879     }
17880
17881   clutter_actor_queue_redraw (self);
17882
17883   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17884 }
17885
17886 /**
17887  * clutter_actor_get_content_gravity:
17888  * @self: a #ClutterActor
17889  *
17890  * Retrieves the content gravity as set using
17891  * clutter_actor_get_content_gravity().
17892  *
17893  * Return value: the content gravity
17894  *
17895  * Since: 1.10
17896  */
17897 ClutterContentGravity
17898 clutter_actor_get_content_gravity (ClutterActor *self)
17899 {
17900   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17901                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17902
17903   return self->priv->content_gravity;
17904 }
17905
17906 /**
17907  * clutter_actor_get_content_box:
17908  * @self: a #ClutterActor
17909  * @box: (out caller-allocates): the return location for the bounding
17910  *   box for the #ClutterContent
17911  *
17912  * Retrieves the bounding box for the #ClutterContent of @self.
17913  *
17914  * The bounding box is relative to the actor's allocation.
17915  *
17916  * If no #ClutterContent is set for @self, or if @self has not been
17917  * allocated yet, then the result is undefined.
17918  *
17919  * The content box is guaranteed to be, at most, as big as the allocation
17920  * of the #ClutterActor.
17921  *
17922  * If the #ClutterContent used by the actor has a preferred size, then
17923  * it is possible to modify the content box by using the
17924  * #ClutterActor:content-gravity property.
17925  *
17926  * Since: 1.10
17927  */
17928 void
17929 clutter_actor_get_content_box (ClutterActor    *self,
17930                                ClutterActorBox *box)
17931 {
17932   ClutterActorPrivate *priv;
17933   gfloat content_w, content_h;
17934   gfloat alloc_w, alloc_h;
17935
17936   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17937   g_return_if_fail (box != NULL);
17938
17939   priv = self->priv;
17940
17941   box->x1 = 0.f;
17942   box->y1 = 0.f;
17943   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17944   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17945
17946   if (priv->content_box_valid)
17947     {
17948       *box = priv->content_box;
17949       return;
17950     }
17951
17952   /* no need to do any more work */
17953   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17954     return;
17955
17956   if (priv->content == NULL)
17957     return;
17958
17959   /* if the content does not have a preferred size then there is
17960    * no point in computing the content box
17961    */
17962   if (!clutter_content_get_preferred_size (priv->content,
17963                                            &content_w,
17964                                            &content_h))
17965     return;
17966
17967   alloc_w = box->x2;
17968   alloc_h = box->y2;
17969
17970   switch (priv->content_gravity)
17971     {
17972     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17973       box->x2 = box->x1 + MIN (content_w, alloc_w);
17974       box->y2 = box->y1 + MIN (content_h, alloc_h);
17975       break;
17976
17977     case CLUTTER_CONTENT_GRAVITY_TOP:
17978       if (alloc_w > content_w)
17979         {
17980           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17981           box->x2 = box->x1 + content_w;
17982         }
17983       box->y2 = box->y1 + MIN (content_h, alloc_h);
17984       break;
17985
17986     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17987       if (alloc_w > content_w)
17988         {
17989           box->x1 += (alloc_w - content_w);
17990           box->x2 = box->x1 + content_w;
17991         }
17992       box->y2 = box->y1 + MIN (content_h, alloc_h);
17993       break;
17994
17995     case CLUTTER_CONTENT_GRAVITY_LEFT:
17996       box->x2 = box->x1 + MIN (content_w, alloc_w);
17997       if (alloc_h > content_h)
17998         {
17999           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18000           box->y2 = box->y1 + content_h;
18001         }
18002       break;
18003
18004     case CLUTTER_CONTENT_GRAVITY_CENTER:
18005       if (alloc_w > content_w)
18006         {
18007           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18008           box->x2 = box->x1 + content_w;
18009         }
18010       if (alloc_h > content_h)
18011         {
18012           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18013           box->y2 = box->y1 + content_h;
18014         }
18015       break;
18016
18017     case CLUTTER_CONTENT_GRAVITY_RIGHT:
18018       if (alloc_w > content_w)
18019         {
18020           box->x1 += (alloc_w - content_w);
18021           box->x2 = box->x1 + content_w;
18022         }
18023       if (alloc_h > content_h)
18024         {
18025           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18026           box->y2 = box->y1 + content_h;
18027         }
18028       break;
18029
18030     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18031       box->x2 = box->x1 + MIN (content_w, alloc_w);
18032       if (alloc_h > content_h)
18033         {
18034           box->y1 += (alloc_h - content_h);
18035           box->y2 = box->y1 + content_h;
18036         }
18037       break;
18038
18039     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18040       if (alloc_w > content_w)
18041         {
18042           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18043           box->x2 = box->x1 + content_w;
18044         }
18045       if (alloc_h > content_h)
18046         {
18047           box->y1 += (alloc_h - content_h);
18048           box->y2 = box->y1 + content_h;
18049         }
18050       break;
18051
18052     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18053       if (alloc_w > content_w)
18054         {
18055           box->x1 += (alloc_w - content_w);
18056           box->x2 = box->x1 + content_w;
18057         }
18058       if (alloc_h > content_h)
18059         {
18060           box->y1 += (alloc_h - content_h);
18061           box->y2 = box->y1 + content_h;
18062         }
18063       break;
18064
18065     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18066       g_assert_not_reached ();
18067       break;
18068
18069     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18070       {
18071         double r_c = content_w / content_h;
18072         double r_a = alloc_w / alloc_h;
18073
18074         if (r_c >= 1.0)
18075           {
18076             if (r_a >= 1.0)
18077               {
18078                 box->x1 = 0.f;
18079                 box->x2 = alloc_w;
18080
18081                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18082                 box->y2 = box->y1 + (alloc_w * r_c);
18083               }
18084             else
18085               {
18086                 box->y1 = 0.f;
18087                 box->y2 = alloc_h;
18088
18089                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18090                 box->x2 = box->x1 + (alloc_h * r_c);
18091               }
18092           }
18093         else
18094           {
18095             if (r_a >= 1.0)
18096               {
18097                 box->y1 = 0.f;
18098                 box->y2 = alloc_h;
18099
18100                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18101                 box->x2 = box->x1 + (alloc_h * r_c);
18102               }
18103             else
18104               {
18105                 box->x1 = 0.f;
18106                 box->x2 = alloc_w;
18107
18108                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18109                 box->y2 = box->y1 + (alloc_w * r_c);
18110               }
18111           }
18112       }
18113       break;
18114     }
18115 }
18116
18117 /**
18118  * clutter_actor_set_content_scaling_filters:
18119  * @self: a #ClutterActor
18120  * @min_filter: the minification filter for the content
18121  * @mag_filter: the magnification filter for the content
18122  *
18123  * Sets the minification and magnification filter to be applied when
18124  * scaling the #ClutterActor:content of a #ClutterActor.
18125  *
18126  * The #ClutterActor:minification-filter will be used when reducing
18127  * the size of the content; the #ClutterActor:magnification-filter
18128  * will be used when increasing the size of the content.
18129  *
18130  * Since: 1.10
18131  */
18132 void
18133 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18134                                            ClutterScalingFilter  min_filter,
18135                                            ClutterScalingFilter  mag_filter)
18136 {
18137   ClutterActorPrivate *priv;
18138   gboolean changed;
18139   GObject *obj;
18140
18141   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18142
18143   priv = self->priv;
18144   obj = G_OBJECT (self);
18145
18146   g_object_freeze_notify (obj);
18147
18148   changed = FALSE;
18149
18150   if (priv->min_filter != min_filter)
18151     {
18152       priv->min_filter = min_filter;
18153       changed = TRUE;
18154
18155       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18156     }
18157
18158   if (priv->mag_filter != mag_filter)
18159     {
18160       priv->mag_filter = mag_filter;
18161       changed = TRUE;
18162
18163       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18164     }
18165
18166   if (changed)
18167     clutter_actor_queue_redraw (self);
18168
18169   g_object_thaw_notify (obj);
18170 }
18171
18172 /**
18173  * clutter_actor_get_content_scaling_filters:
18174  * @self: a #ClutterActor
18175  * @min_filter: (out) (allow-none): return location for the minification
18176  *   filter, or %NULL
18177  * @mag_filter: (out) (allow-none): return location for the magnification
18178  *   filter, or %NULL
18179  *
18180  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18181  *
18182  * Since: 1.10
18183  */
18184 void
18185 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18186                                            ClutterScalingFilter *min_filter,
18187                                            ClutterScalingFilter *mag_filter)
18188 {
18189   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18190
18191   if (min_filter != NULL)
18192     *min_filter = self->priv->min_filter;
18193
18194   if (mag_filter != NULL)
18195     *mag_filter = self->priv->mag_filter;
18196 }