actor: Clear MetaGroups when empty
[profile/ivi/clutter.git] / clutter / clutter-actor.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *
8  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd
9  * Copyright (C) 2009, 2010, 2011, 2012 Intel Corp
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 /**
26  * SECTION:clutter-actor
27  * @short_description: The basic element of the scene graph 
28  *
29  * The ClutterActor class is the basic element of the scene graph in Clutter,
30  * and it encapsulates the position, size, and transformations of a node in
31  * the graph.
32  *
33  * <refsect2 id="ClutterActor-transformations">
34  *   <title>Actor transformations</title>
35  *   <para>Each actor can be transformed using methods like
36  *   clutter_actor_set_scale() or clutter_actor_set_rotation(). The order
37  *   in which the transformations are applied is decided by Clutter and it is
38  *   the following:</para>
39  *   <orderedlist>
40  *     <listitem><para>translation by the origin of the #ClutterActor:allocation;</para></listitem>
41  *     <listitem><para>translation by the actor's #ClutterActor:depth;</para></listitem>
42  *     <listitem><para>scaling by the #ClutterActor:scale-x and #ClutterActor:scale-y factors;</para></listitem>
43  *     <listitem><para>rotation around the #ClutterActor:rotation-z-angle and #ClutterActor:rotation-z-center;</para></listitem>
44  *     <listitem><para>rotation around the #ClutterActor:rotation-y-angle and #ClutterActor:rotation-y-center;</para></listitem>
45  *     <listitem><para>rotation around the #ClutterActor:rotation-x-angle and #ClutterActor:rotation-x-center;</para></listitem>
46  *     <listitem><para>negative translation by the #ClutterActor:anchor-x and #ClutterActor:anchor-y point.</para></listitem>
47  *   </orderedlist>
48  * </refsect2>
49  *
50  * <refsect2 id="ClutterActor-geometry">
51  *   <title>Modifying an actor's geometry</title>
52  *   <para>Each actor has a bounding box, called #ClutterActor:allocation
53  *   which is either set by its parent or explicitly through the
54  *   clutter_actor_set_position() and clutter_actor_set_size() methods.
55  *   Each actor also has an implicit preferred size.</para>
56  *   <para>An actor’s preferred size can be defined by any subclass by
57  *   overriding the #ClutterActorClass.get_preferred_width() and the
58  *   #ClutterActorClass.get_preferred_height() virtual functions, or it can
59  *   be explicitly set by using clutter_actor_set_width() and
60  *   clutter_actor_set_height().</para>
61  *   <para>An actor’s position can be set explicitly by using
62  *   clutter_actor_set_x() and clutter_actor_set_y(); the coordinates are
63  *   relative to the origin of the actor’s parent.</para>
64  * </refsect2>
65  *
66  * <refsect2 id="ClutterActor-children">
67  *   <title>Managing actor children</title>
68  *   <para>Each actor can have multiple children, by calling
69  *   clutter_actor_add_child() to add a new child actor, and
70  *   clutter_actor_remove_child() to remove an existing child. #ClutterActor
71  *   will hold a reference on each child actor, which will be released when
72  *   the child is removed from its parent, or destroyed using
73  *   clutter_actor_destroy().</para>
74  *   <informalexample><programlisting>
75  *  ClutterActor *actor = clutter_actor_new ();
76  *
77  *  /&ast; set the bounding box of the actor &ast;/
78  *  clutter_actor_set_position (actor, 0, 0);
79  *  clutter_actor_set_size (actor, 480, 640);
80  *
81  *  /&ast; set the background color of the actor &ast;/
82  *  clutter_actor_set_background_color (actor, CLUTTER_COLOR_Orange);
83  *
84  *  /&ast; set the bounding box of the child, relative to the parent &ast;/
85  *  ClutterActor *child = clutter_actor_new ();
86  *  clutter_actor_set_position (child, 20, 20);
87  *  clutter_actor_set_size (child, 80, 240);
88  *
89  *  /&ast; set the background color of the child &ast;/
90  *  clutter_actor_set_background_color (child, CLUTTER_COLOR_Blue);
91  *
92  *  /&ast; add the child to the actor &ast;/
93  *  clutter_actor_add_child (actor, child);
94  *   </programlisting></informalexample>
95  *   <para>Children can be inserted at a given index, or above and below
96  *   another child actor. The order of insertion determines the order of the
97  *   children when iterating over them. Iterating over children is performed
98  *   by using clutter_actor_get_first_child(), clutter_actor_get_previous_sibling(),
99  *   clutter_actor_get_next_sibling(), and clutter_actor_get_last_child(). It is
100  *   also possible to retrieve a list of children by using
101  *   clutter_actor_get_children(), as well as retrieving a specific child at a
102  *   given index by using clutter_actor_get_child_at_index().</para>
103  *   <para>If you need to track additions of children to a #ClutterActor, use
104  *   the #ClutterContainer::actor-added signal; similarly, to track removals
105  *   of children from a ClutterActor, use the #ClutterContainer::actor-removed
106  *   signal.</para>
107  *   <informalexample><programlisting>
108  * <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../tests/interactive/test-actor.c">
109  *   <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
110  * </xi:include>
111  *   </programlisting></informalexample>
112  *   <figure id="actor-example-image">
113  *     <title>Actors</title>
114  *     <graphic fileref="actor-example.png" format="PNG"/>
115  *   </figure>
116  * </refsect2>
117  *
118  * <refsect2 id="ClutterActor-painting">
119  *   <title>Painting an actor</title>
120  *   <para>There are three ways to paint an actor:</para>
121  *   <itemizedlist>
122  *     <listitem><para>set a delegate #ClutterContent as the value for the
123  *     #ClutterActor:content property of the actor;</para></listitem>
124  *     <listitem><para>subclass #ClutterActor and override the
125  *     #ClutterActorClass.paint_node() virtual function;</para></listitem>
126  *     <listitem><para>subclass #ClutterActor and override the
127  *     #ClutterActorClass.paint() virtual function.</para></listitem>
128  *   </itemizedlist>
129  *   <formalpara>
130  *     <title>Setting the Content property</title>
131  *     <para>A #ClutterContent is a delegate object that takes over the
132  *     painting operation of one, or more actors. The #ClutterContent
133  *     painting will be performed on top of the #ClutterActor:background-color
134  *     of the actor, and before calling the #ClutterActorClass.paint_node()
135  *     virtual function.</para>
136  *     <informalexample><programlisting>
137  * ClutterActor *actor = clutter_actor_new ();
138  *
139  * /&ast; set the bounding box &ast;/
140  * clutter_actor_set_position (actor, 50, 50);
141  * clutter_actor_set_size (actor, 100, 100);
142  *
143  * /&ast; set the content; the image_content variable is set elsewhere &ast;/
144  * clutter_actor_set_content (actor, image_content);
145  *     </programlisting></informalexample>
146  *   </formalpara>
147  *   <formalpara>
148  *     <title>Overriding the paint_node virtual function</title>
149  *     <para>The #ClutterActorClass.paint_node() virtual function is invoked
150  *     whenever an actor needs to be painted. The implementation of the
151  *     virtual function must only paint the contents of the actor itself,
152  *     and not the contents of its children, if the actor has any.</para>
153  *     <para>The #ClutterPaintNode passed to the virtual function is the
154  *     local root of the render tree; any node added to it will be
155  *     rendered at the correct position, as defined by the actor's
156  *     #ClutterActor:allocation.</para>
157  *     <informalexample><programlisting>
158  * static void
159  * my_actor_paint_node (ClutterActor     *actor,
160  *                      ClutterPaintNode *root)
161  * {
162  *   ClutterPaintNode *node;
163  *   ClutterActorBox box;
164  *
165  *   /&ast; where the content of the actor should be painted &ast;/
166  *   clutter_actor_get_allocation_box (actor, &box);
167  *
168  *   /&ast; the cogl_texture variable is set elsewhere &ast;/
169  *   node = clutter_texture_node_new (cogl_texture, CLUTTER_COLOR_White,
170  *                                    CLUTTER_SCALING_FILTER_TRILINEAR,
171  *                                    CLUTTER_SCALING_FILTER_LINEAR);
172  *
173  *   /&ast; paint the content of the node using the allocation &ast;/
174  *   clutter_paint_node_add_rectangle (node, &box);
175  *
176  *   /&ast; add the node, and transfer ownership &ast;/
177  *   clutter_paint_node_add_child (root, node);
178  *   clutter_paint_node_unref (node);
179  * }
180  *     </programlisting></informalexample>
181  *   </formalpara>
182  *   <formalpara>
183  *     <title>Overriding the paint virtual function</title>
184  *     <para>The #ClutterActorClass.paint() virtual function is invoked
185  *     when the #ClutterActor::paint signal is emitted, and after the other
186  *     signal handlers have been invoked. Overriding the paint virtual
187  *     function gives total control to the paint sequence of the actor
188  *     itself, including the children of the actor, if any.</para>
189  *     <warning><para>It is strongly discouraged to override the
190  *     #ClutterActorClass.paint() virtual function, as well as connecting
191  *     to the #ClutterActor::paint signal. These hooks into the paint
192  *     sequence are considered legacy, and will be removed when the Clutter
193  *     API changes.</para></warning>
194  *   </formalpara>
195  * </refsect2>
196  *
197  * <refsect2 id="ClutterActor-events">
198  *   <title>Handling events on an actor</title>
199  *   <para>A #ClutterActor can receive and handle input device events, for
200  *   instance pointer events and key events, as long as its
201  *   #ClutterActor:reactive property is set to %TRUE.</para>
202  *   <para>Once an actor has been determined to be the source of an event,
203  *   Clutter will traverse the scene graph from the top-level actor towards the
204  *   event source, emitting the #ClutterActor::captured-event signal on each
205  *   ancestor until it reaches the source; this phase is also called
206  *   <emphasis>the capture phase</emphasis>. If the event propagation was not
207  *   stopped, the graph is walked backwards, from the source actor to the
208  *   top-level, and the #ClutterActor::event signal, along with other event
209  *   signals if needed, is emitted; this phase is also called <emphasis>the
210  *   bubble phase</emphasis>. At any point of the signal emission, signal
211  *   handlers can stop the propagation through the scene graph by returning
212  *   %CLUTTER_EVENT_STOP; otherwise, they can continue the propagation by
213  *   returning %CLUTTER_EVENT_PROPAGATE.</para>
214  * </refsect2>
215  *
216  * <refsect2 id="ClutterActor-animation">
217  *   <title>Animation</title>
218  *   <para>Animation is a core concept of modern user interfaces; Clutter
219  *   provides a complete and powerful animation framework that automatically
220  *   tweens the actor's state without requiring direct, frame by frame
221  *   manipulation from your application code.</para>
222  *   <formalpara>
223  *     <title>Implicit animations</title>
224  *     <para>The implicit animation model of Clutter assumes that all the
225  *     changes in an actor state should be gradual and asynchronous; Clutter
226  *     will automatically transition an actor's property change between the
227  *     current state and the desired one without manual intervention.</para>
228  *     <para>By default, in the 1.0 API series, the transition happens with
229  *     a duration of zero milliseconds, and the implicit animation is an
230  *     opt in feature to retain backwards compatibility. In order to enable
231  *     implicit animations, it is necessary to change the easing state of
232  *     an actor by using clutter_actor_save_easing_state():</para>
233  *     <informalexample><programlisting>
234  * /&ast; assume that the actor is currently positioned at (100, 100) &ast;/
235  * clutter_actor_save_easing_state (actor);
236  * clutter_actor_set_position (actor, 500, 500);
237  * clutter_actor_restore_easing_state (actor);
238  *     </programlisting></informalexample>
239  *     <para>The example above will trigger an implicit animation of the
240  *     actor between its current position to a new position.</para>
241  *     <para>It is possible to animate multiple properties of an actor
242  *     at the same time, and you can animate multiple actors at the same
243  *     time as well, for instance:</para>
244  *     <informalexample><programlisting>
245  * /&ast; animate the actor's opacity and depth &ast;/
246  * clutter_actor_save_easing_state (actor);
247  * clutter_actor_set_opacity (actor, 0);
248  * clutter_actor_set_depth (actor, -100);
249  * clutter_actor_restore_easing_state (actor);
250  *
251  * /&ast; animate another actor's opacity &ast;/
252  * clutter_actor_save_easing_state (another_actor);
253  * clutter_actor_set_opacity (another_actor, 255);
254  * clutter_actor_set_depth (another_actor, 100);
255  * clutter_actor_restore_easing_state (another_actor);
256  *     </programlisting></informalexample>
257  *     <para>Implicit animations use a default duration of 250 milliseconds,
258  *     and a default easing mode of %CLUTTER_EASE_OUT_CUBIC, unless you call
259  *     clutter_actor_set_easing_mode() and clutter_actor_set_easing_duration()
260  *     after changing the easing state of the actor.</para>
261  *     <para>It is important to note that if you modify the state on an
262  *     animatable property while a transition is in flight, the transition's
263  *     final value will be updated, as well as its duration and progress
264  *     mode by using the current easing state; for instance, in the following
265  *     example:</para>
266  *     <informalexample><programlisting>
267  * clutter_actor_save_easing_state (actor);
268  * clutter_actor_set_x (actor, 200);
269  * clutter_actor_restore_easing_state (actor);
270  *
271  * clutter_actor_save_easing_state (actor);
272  * clutter_actor_set_x (actor, 100);
273  * clutter_actor_restore_easing_state (actor);
274  *     </programlisting></informalexample>
275  *     <para>the first call to clutter_actor_set_x() will begin a transition
276  *     of the #ClutterActor:x property to the value of 200; the second call
277  *     to clutter_actor_set_x() will change the transition's final value to
278  *     100.</para>
279  *     <para>It is possible to retrieve the #ClutterTransition used by the
280  *     animatable properties by using clutter_actor_get_transition() and using
281  *     the property name as the transition name.</para>
282  *   </formalpara>
283  *   <formalpara>
284  *     <title>Explicit animations</title>
285  *     <para>The explicit animation model supported by Clutter requires that
286  *     you create a #ClutterTransition object, and set the initial and
287  *     final values. The transition will not start unless you add it to the
288  *     #ClutterActor.</para>
289  *     <informalexample><programlisting>
290  * ClutterTransition *transition;
291  *
292  * transition = clutter_property_transition_new ("opacity");
293  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 3000);
294  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2);
295  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
296  * clutter_transition_set_interval (transition, clutter_interval_new (G_TYPE_UINT, 255, 0));
297  *
298  * clutter_actor_add_transition (actor, "animate-opacity", transition);
299  *     </programlisting></informalexample>
300  *     <para>The example above will animate the #ClutterActor:opacity property
301  *     of an actor between fully opaque and fully transparent, and back, over
302  *     a span of 3 seconds. The animation does not begin until it is added to
303  *     the actor.</para>
304  *     <para>The explicit animation API should also be used when using custom
305  *     animatable properties for #ClutterAction, #ClutterConstraint, and
306  *     #ClutterEffect instances associated to an actor; see the section on
307  *     <ulink linkend="ClutterActor-custom-animatable-properties">custom
308  *     animatable properties below</ulink> for an example.</para>
309  *     <para>Finally, explicit animations are useful for creating animations
310  *     that run continuously, for instance:</para>
311  *     <informalexample><programlisting>
312  * /&ast; this animation will pulse the actor's opacity continuously &ast;/
313  * ClutterTransition *transition;
314  * ClutterInterval *interval;
315  *
316  * transition = clutter_property_transition_new ("opacity");
317  *
318  * /&ast; we want to animate the opacity between 0 and 255 &ast;/
319  * internal = clutter_interval_new (G_TYPE_UINT, 0, 255);
320  * clutter_transition_set_interval (transition, interval);
321  *
322  * /&ast; over a one second duration, running an infinite amount of times &ast;/
323  * clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 1000);
324  * clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), -1);
325  *
326  * /&ast; we want to fade in and out, so we need to auto-reverse the transition &ast;/
327  * clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE);
328  *
329  * /&ast; and we want to use an easing function that eases both in and out &ast;/
330  * clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
331  *                                     CLUTTER_EASE_IN_OUT_CUBIC);
332  *
333  * /&ast; add the transition to the desired actor; this will
334  *  &ast; start the animation.
335  *  &ast;/
336  * clutter_actor_add_transition (actor, "opacityAnimation", transition);
337  *     </programlisting></informalexample>
338  *   </formalpara>
339  * </refsect2>
340  *
341  * <refsect2 id="ClutterActor-subclassing">
342  *   <title>Implementing an actor</title>
343  *   <para>Careful consideration should be given when deciding to implement
344  *   a #ClutterActor sub-class. It is generally recommended to implement a
345  *   sub-class of #ClutterActor only for actors that should be used as leaf
346  *   nodes of a scene graph.</para>
347  *   <para>If your actor should be painted in a custom way, you should
348  *   override the #ClutterActor::paint signal class handler. You can either
349  *   opt to chain up to the parent class implementation or decide to fully
350  *   override the default paint implementation; Clutter will set up the
351  *   transformations and clip regions prior to emitting the #ClutterActor::paint
352  *   signal.</para>
353  *   <para>By overriding the #ClutterActorClass.get_preferred_width() and
354  *   #ClutterActorClass.get_preferred_height() virtual functions it is
355  *   possible to change or provide the preferred size of an actor; similarly,
356  *   by overriding the #ClutterActorClass.allocate() virtual function it is
357  *   possible to control the layout of the children of an actor. Make sure to
358  *   always chain up to the parent implementation of the
359  *   #ClutterActorClass.allocate() virtual function.</para>
360  *   <para>In general, it is strongly encouraged to use delegation and
361  *   composition instead of direct subclassing.</para>
362  * </refsect2>
363  *
364  * <refsect2 id="ClutterActor-script">
365  *   <title>ClutterActor custom properties for #ClutterScript</title>
366  *   <para>#ClutterActor defines a custom "rotation" property which
367  *   allows a short-hand description of the rotations to be applied
368  *   to an actor.</para>
369  *   <para>The syntax of the "rotation" property is the following:</para>
370  *   <informalexample>
371  *     <programlisting>
372  * "rotation" : [
373  *   { "&lt;axis&gt;" : [ &lt;angle&gt;, [ &lt;center&gt; ] ] }
374  * ]
375  *     </programlisting>
376  *   </informalexample>
377  *   <para>where the <emphasis>axis</emphasis> is the name of an enumeration
378  *   value of type #ClutterRotateAxis and <emphasis>angle</emphasis> is a
379  *   floating point value representing the rotation angle on the given axis,
380  *   in degrees.</para>
381  *   <para>The <emphasis>center</emphasis> array is optional, and if present
382  *   it must contain the center of rotation as described by two coordinates:
383  *   Y and Z for "x-axis"; X and Z for "y-axis"; and X and Y for
384  *   "z-axis".</para>
385  *   <para>#ClutterActor will also parse every positional and dimensional
386  *   property defined as a string through clutter_units_from_string(); you
387  *   should read the documentation for the #ClutterUnits parser format for
388  *   the valid units and syntax.</para>
389  * </refsect2>
390  *
391  * <refsect2 id="ClutterActor-custom-animatable-properties">
392  *   <title>Custom animatable properties</title>
393  *   <para>#ClutterActor allows accessing properties of #ClutterAction,
394  *   #ClutterEffect, and #ClutterConstraint instances associated to an actor
395  *   instance for animation purposes.</para>
396  *   <para>In order to access a specific #ClutterAction or a #ClutterConstraint
397  *   property it is necessary to set the #ClutterActorMeta:name property on the
398  *   given action or constraint.</para>
399  *   <para>The property can be accessed using the following syntax:</para>
400  *   <informalexample>
401  *     <programlisting>
402  * @&lt;section&gt;.&lt;meta-name&gt;.&lt;property-name&gt;
403  *     </programlisting>
404  *   </informalexample>
405  *   <para>The initial <emphasis>@</emphasis> is mandatory.</para>
406  *   <para>The <emphasis>section</emphasis> fragment can be one between
407  *   "actions", "constraints" and "effects".</para>
408  *   <para>The <emphasis>meta-name</emphasis> fragment is the name of the
409  *   action or constraint, as specified by the #ClutterActorMeta:name
410  *   property.</para>
411  *   <para>The <emphasis>property-name</emphasis> fragment is the name of the
412  *   action or constraint property to be animated.</para>
413  *   <para>The example below animates a #ClutterBindConstraint applied to an
414  *   actor using clutter_actor_animate(). The <emphasis>rect</emphasis> has
415  *   a binding constraint for the <emphasis>origin</emphasis> actor, and in
416  *   its initial state is overlapping the actor to which is bound to.</para>
417  *   <informalexample><programlisting>
418  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_X, 0.0);
419  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-x");
420  * clutter_actor_add_constraint (rect, constraint);
421  *
422  * constraint = clutter_bind_constraint_new (origin, CLUTTER_BIND_Y, 0.0);
423  * clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), "bind-y");
424  * clutter_actor_add_constraint (rect, constraint);
425  *
426  * clutter_actor_set_reactive (origin, TRUE);
427  *
428  * g_signal_connect (origin, "button-press-event",
429  *                   G_CALLBACK (on_button_press),
430  *                   rect);
431  *   </programlisting></informalexample>
432  *   <para>On button press, the rectangle "slides" from behind the actor to
433  *   which is bound to, using the #ClutterBindConstraint:offset property to
434  *   achieve the effect:</para>
435  *   <informalexample><programlisting>
436  * gboolean
437  * on_button_press (ClutterActor *origin,
438  *                  ClutterEvent *event,
439  *                  ClutterActor *rect)
440  * {
441  *   ClutterTransition *transition;
442  *   ClutterInterval *interval;
443  *
444  *   /&ast; the offset that we want to apply; this will make the actor
445  *    &ast; slide in from behind the origin and rest at the right of
446  *    &ast; the origin, plus a padding value.
447  *    &ast;/
448  *   float new_offset = clutter_actor_get_width (origin) + h_padding;
449  *
450  *   /&ast; the property we wish to animate; the "@constraints" section
451  *    &ast; tells Clutter to check inside the constraints associated
452  *    &ast; with the actor; the "bind-x" section is the name of the
453  *    &ast; constraint; and the "offset" is the name of the property
454  *    &ast; on the constraint.
455  *    &ast;/
456  *   const char *prop = "@constraints.bind-x.offset";
457  *
458  *   /&ast; create a new transition for the given property &ast;/
459  *   transition = clutter_property_transition_new (prop);
460  *
461  *   /&ast; set the easing mode and duration &ast;/
462  *   clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
463  *                                       CLUTTER_EASE_OUT_CUBIC);
464  *   clutter_timeline_set_duration (CLUTTER_TIMELINE (transition), 500);
465  *
466  *   /&ast; create the interval with the initial and final values &ast;/
467  *   interval = clutter_interval_new (G_TYPE_FLOAT, 0, new_offset);
468  *   clutter_transition_set_interval (transition, interval);
469  *
470  *   /&ast; add the transition to the actor; this causes the animation
471  *    &ast; to start. the name "offsetAnimation" can be used to retrieve
472  *    &ast; the transition later.
473  *    &ast;/
474  *   clutter_actor_add_transition (rect, "offsetAnimation", transition);
475  *
476  *   /&ast; we handled the event &ast;/
477  *   return CLUTTER_EVENT_STOP;
478  * }
479  *   </programlisting></informalexample>
480  * </refsect2>
481  */
482
483 /**
484  * CLUTTER_ACTOR_IS_MAPPED:
485  * @a: a #ClutterActor
486  *
487  * Evaluates to %TRUE if the %CLUTTER_ACTOR_MAPPED flag is set.
488  *
489  * The mapped state is set when the actor is visible and all its parents up
490  * to a top-level (e.g. a #ClutterStage) are visible, realized, and mapped.
491  *
492  * This check can be used to see if an actor is going to be painted, as only
493  * actors with the %CLUTTER_ACTOR_MAPPED flag set are going to be painted.
494  *
495  * The %CLUTTER_ACTOR_MAPPED flag is managed by Clutter itself, and it should
496  * not be checked directly; instead, the recommended usage is to connect a
497  * handler on the #GObject::notify signal for the #ClutterActor:mapped
498  * property of #ClutterActor, and check the presence of
499  * the %CLUTTER_ACTOR_MAPPED flag on state changes.
500  *
501  * It is also important to note that Clutter may delay the changes of
502  * the %CLUTTER_ACTOR_MAPPED flag on top-levels due to backend-specific
503  * limitations, or during the reparenting of an actor, to optimize
504  * unnecessary (and potentially expensive) state changes.
505  *
506  * Since: 0.2
507  */
508
509 /**
510  * CLUTTER_ACTOR_IS_REALIZED:
511  * @a: a #ClutterActor
512  *
513  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REALIZED flag is set.
514  *
515  * The realized state has an actor-dependant interpretation. If an
516  * actor wants to delay allocating resources until it is attached to a
517  * stage, it may use the realize state to do so. However it is
518  * perfectly acceptable for an actor to allocate Cogl resources before
519  * being realized because there is only one drawing context used by Clutter
520  * so any resources will work on any stage.  If an actor is mapped it
521  * must also be realized, but an actor can be realized and unmapped
522  * (this is so hiding an actor temporarily doesn't do an expensive
523  * unrealize/realize).
524  *
525  * To be realized an actor must be inside a stage, and all its parents
526  * must be realized.
527  *
528  * Since: 0.2
529  */
530
531 /**
532  * CLUTTER_ACTOR_IS_VISIBLE:
533  * @a: a #ClutterActor
534  *
535  * Evaluates to %TRUE if the actor has been shown, %FALSE if it's hidden.
536  * Equivalent to the ClutterActor::visible object property.
537  *
538  * Note that an actor is only painted onscreen if it's mapped, which
539  * means it's visible, and all its parents are visible, and one of the
540  * parents is a toplevel stage; see also %CLUTTER_ACTOR_IS_MAPPED.
541  *
542  * Since: 0.2
543  */
544
545 /**
546  * CLUTTER_ACTOR_IS_REACTIVE:
547  * @a: a #ClutterActor
548  *
549  * Evaluates to %TRUE if the %CLUTTER_ACTOR_REACTIVE flag is set.
550  *
551  * Only reactive actors will receive event-related signals.
552  *
553  * Since: 0.6
554  */
555
556 #ifdef HAVE_CONFIG_H
557 #include "config.h"
558 #endif
559
560 #include <math.h>
561
562 #include <gobject/gvaluecollector.h>
563
564 #include <cogl/cogl.h>
565
566 #define CLUTTER_DISABLE_DEPRECATION_WARNINGS
567 #define CLUTTER_ENABLE_EXPERIMENTAL_API
568
569 #include "clutter-actor-private.h"
570
571 #include "clutter-action.h"
572 #include "clutter-actor-meta-private.h"
573 #include "clutter-animatable.h"
574 #include "clutter-color-static.h"
575 #include "clutter-color.h"
576 #include "clutter-constraint.h"
577 #include "clutter-container.h"
578 #include "clutter-content-private.h"
579 #include "clutter-debug.h"
580 #include "clutter-effect-private.h"
581 #include "clutter-enum-types.h"
582 #include "clutter-fixed-layout.h"
583 #include "clutter-flatten-effect.h"
584 #include "clutter-interval.h"
585 #include "clutter-main.h"
586 #include "clutter-marshal.h"
587 #include "clutter-paint-nodes.h"
588 #include "clutter-paint-node-private.h"
589 #include "clutter-paint-volume-private.h"
590 #include "clutter-private.h"
591 #include "clutter-profile.h"
592 #include "clutter-property-transition.h"
593 #include "clutter-scriptable.h"
594 #include "clutter-script-private.h"
595 #include "clutter-stage-private.h"
596 #include "clutter-timeline.h"
597 #include "clutter-transition.h"
598 #include "clutter-units.h"
599
600 #include "deprecated/clutter-actor.h"
601 #include "deprecated/clutter-behaviour.h"
602 #include "deprecated/clutter-container.h"
603
604 #define CLUTTER_ACTOR_GET_PRIVATE(obj) \
605 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_ACTOR, ClutterActorPrivate))
606
607 /* Internal enum used to control mapped state update.  This is a hint
608  * which indicates when to do something other than just enforce
609  * invariants.
610  */
611 typedef enum {
612   MAP_STATE_CHECK,           /* just enforce invariants. */
613   MAP_STATE_MAKE_UNREALIZED, /* force unrealize, ignoring invariants,
614                               * used when about to unparent.
615                               */
616   MAP_STATE_MAKE_MAPPED,     /* set mapped, error if invariants not met;
617                               * used to set mapped on toplevels.
618                               */
619   MAP_STATE_MAKE_UNMAPPED    /* set unmapped, even if parent is mapped,
620                               * used just before unmapping parent.
621                               */
622 } MapStateChange;
623
624 /* 3 entries should be a good compromise, few layout managers
625  * will ask for 3 different preferred size in each allocation cycle */
626 #define N_CACHED_SIZE_REQUESTS 3
627
628 struct _ClutterActorPrivate
629 {
630   /* request mode */
631   ClutterRequestMode request_mode;
632
633   /* our cached size requests for different width / height */
634   SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
635   SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
636
637   /* An age of 0 means the entry is not set */
638   guint cached_height_age;
639   guint cached_width_age;
640
641   /* the bounding box of the actor, relative to the parent's
642    * allocation
643    */
644   ClutterActorBox allocation;
645   ClutterAllocationFlags allocation_flags;
646
647   /* clip, in actor coordinates */
648   cairo_rectangle_t clip;
649
650   /* the cached transformation matrix; see apply_transform() */
651   CoglMatrix transform;
652
653   guint8 opacity;
654   gint opacity_override;
655
656   ClutterOffscreenRedirect offscreen_redirect;
657
658   /* This is an internal effect used to implement the
659      offscreen-redirect property */
660   ClutterEffect *flatten_effect;
661
662   /* scene graph */
663   ClutterActor *parent;
664   ClutterActor *prev_sibling;
665   ClutterActor *next_sibling;
666   ClutterActor *first_child;
667   ClutterActor *last_child;
668
669   gint n_children;
670
671   /* tracks whenever the children of an actor are changed; the
672    * age is incremented by 1 whenever an actor is added or
673    * removed. the age is not incremented when the first or the
674    * last child pointers are changed, or when grandchildren of
675    * an actor are changed.
676    */
677   gint age;
678
679   gchar *name; /* a non-unique name, used for debugging */
680   guint32 id; /* unique id, used for backward compatibility */
681
682   gint32 pick_id; /* per-stage unique id, used for picking */
683
684   /* a back-pointer to the Pango context that we can use
685    * to create pre-configured PangoLayout
686    */
687   PangoContext *pango_context;
688
689   /* the text direction configured for this child - either by
690    * application code, or by the actor's parent
691    */
692   ClutterTextDirection text_direction;
693
694   /* a counter used to toggle the CLUTTER_INTERNAL_CHILD flag */
695   gint internal_child;
696
697   /* meta classes */
698   ClutterMetaGroup *actions;
699   ClutterMetaGroup *constraints;
700   ClutterMetaGroup *effects;
701
702   /* delegate object used to allocate the children of this actor */
703   ClutterLayoutManager *layout_manager;
704
705   /* delegate object used to paint the contents of this actor */
706   ClutterContent *content;
707
708   ClutterActorBox content_box;
709   ClutterContentGravity content_gravity;
710   ClutterScalingFilter min_filter;
711   ClutterScalingFilter mag_filter;
712
713   /* used when painting, to update the paint volume */
714   ClutterEffect *current_effect;
715
716   /* This is used to store an effect which needs to be redrawn. A
717      redraw can be queued to start from a particular effect. This is
718      used by parametrised effects that can cache an image of the
719      actor. If a parameter of the effect changes then it only needs to
720      redraw the cached image, not the actual actor. The pointer is
721      only valid if is_dirty == TRUE. If the pointer is NULL then the
722      whole actor is dirty. */
723   ClutterEffect *effect_to_redraw;
724
725   /* This is used when painting effects to implement the
726      clutter_actor_continue_paint() function. It points to the node in
727      the list of effects that is next in the chain */
728   const GList *next_effect_to_paint;
729
730   ClutterPaintVolume paint_volume;
731
732   /* NB: This volume isn't relative to this actor, it is in eye
733    * coordinates so that it can remain valid after the actor changes.
734    */
735   ClutterPaintVolume last_paint_volume;
736
737   ClutterStageQueueRedrawEntry *queue_redraw_entry;
738
739   ClutterColor bg_color;
740
741   /* bitfields */
742
743   /* fixed position and sizes */
744   guint position_set                : 1;
745   guint min_width_set               : 1;
746   guint min_height_set              : 1;
747   guint natural_width_set           : 1;
748   guint natural_height_set          : 1;
749   /* cached request is invalid (implies allocation is too) */
750   guint needs_width_request         : 1;
751   /* cached request is invalid (implies allocation is too) */
752   guint needs_height_request        : 1;
753   /* cached allocation is invalid (request has changed, probably) */
754   guint needs_allocation            : 1;
755   guint show_on_set_parent          : 1;
756   guint has_clip                    : 1;
757   guint clip_to_allocation          : 1;
758   guint enable_model_view_transform : 1;
759   guint enable_paint_unmapped       : 1;
760   guint has_pointer                 : 1;
761   guint propagated_one_redraw       : 1;
762   guint paint_volume_valid          : 1;
763   guint last_paint_volume_valid     : 1;
764   guint in_clone_paint              : 1;
765   guint transform_valid             : 1;
766   /* This is TRUE if anything has queued a redraw since we were last
767      painted. In this case effect_to_redraw will point to an effect
768      the redraw was queued from or it will be NULL if the redraw was
769      queued without an effect. */
770   guint is_dirty                    : 1;
771   guint bg_color_set                : 1;
772   guint content_box_valid           : 1;
773 };
774
775 enum
776 {
777   PROP_0,
778
779   PROP_NAME,
780
781   /* X, Y, WIDTH, HEIGHT are "do what I mean" properties;
782    * when set they force a size request, when gotten they
783    * get the allocation if the allocation is valid, and the
784    * request otherwise
785    */
786   PROP_X,
787   PROP_Y,
788   PROP_WIDTH,
789   PROP_HEIGHT,
790
791   /* Then the rest of these size-related properties are the "actual"
792    * underlying properties set or gotten by X, Y, WIDTH, HEIGHT
793    */
794   PROP_FIXED_X,
795   PROP_FIXED_Y,
796
797   PROP_FIXED_POSITION_SET,
798
799   PROP_MIN_WIDTH,
800   PROP_MIN_WIDTH_SET,
801
802   PROP_MIN_HEIGHT,
803   PROP_MIN_HEIGHT_SET,
804
805   PROP_NATURAL_WIDTH,
806   PROP_NATURAL_WIDTH_SET,
807
808   PROP_NATURAL_HEIGHT,
809   PROP_NATURAL_HEIGHT_SET,
810
811   PROP_REQUEST_MODE,
812
813   /* Allocation properties are read-only */
814   PROP_ALLOCATION,
815
816   PROP_DEPTH,
817
818   PROP_CLIP,
819   PROP_HAS_CLIP,
820   PROP_CLIP_TO_ALLOCATION,
821
822   PROP_OPACITY,
823
824   PROP_OFFSCREEN_REDIRECT,
825
826   PROP_VISIBLE,
827   PROP_MAPPED,
828   PROP_REALIZED,
829   PROP_REACTIVE,
830
831   PROP_SCALE_X,
832   PROP_SCALE_Y,
833   PROP_SCALE_CENTER_X,
834   PROP_SCALE_CENTER_Y,
835   PROP_SCALE_GRAVITY,
836
837   PROP_ROTATION_ANGLE_X,
838   PROP_ROTATION_ANGLE_Y,
839   PROP_ROTATION_ANGLE_Z,
840   PROP_ROTATION_CENTER_X,
841   PROP_ROTATION_CENTER_Y,
842   PROP_ROTATION_CENTER_Z,
843   /* This property only makes sense for the z rotation because the
844      others would depend on the actor having a size along the
845      z-axis */
846   PROP_ROTATION_CENTER_Z_GRAVITY,
847
848   PROP_ANCHOR_X,
849   PROP_ANCHOR_Y,
850   PROP_ANCHOR_GRAVITY,
851
852   PROP_SHOW_ON_SET_PARENT,
853
854   PROP_TEXT_DIRECTION,
855   PROP_HAS_POINTER,
856
857   PROP_ACTIONS,
858   PROP_CONSTRAINTS,
859   PROP_EFFECT,
860
861   PROP_LAYOUT_MANAGER,
862
863   PROP_X_ALIGN,
864   PROP_Y_ALIGN,
865   PROP_MARGIN_TOP,
866   PROP_MARGIN_BOTTOM,
867   PROP_MARGIN_LEFT,
868   PROP_MARGIN_RIGHT,
869
870   PROP_BACKGROUND_COLOR,
871   PROP_BACKGROUND_COLOR_SET,
872
873   PROP_FIRST_CHILD,
874   PROP_LAST_CHILD,
875
876   PROP_CONTENT,
877   PROP_CONTENT_GRAVITY,
878   PROP_CONTENT_BOX,
879   PROP_MINIFICATION_FILTER,
880   PROP_MAGNIFICATION_FILTER,
881
882   PROP_LAST
883 };
884
885 static GParamSpec *obj_props[PROP_LAST];
886
887 enum
888 {
889   SHOW,
890   HIDE,
891   DESTROY,
892   PARENT_SET,
893   KEY_FOCUS_IN,
894   KEY_FOCUS_OUT,
895   PAINT,
896   PICK,
897   REALIZE,
898   UNREALIZE,
899   QUEUE_REDRAW,
900   QUEUE_RELAYOUT,
901   EVENT,
902   CAPTURED_EVENT,
903   BUTTON_PRESS_EVENT,
904   BUTTON_RELEASE_EVENT,
905   SCROLL_EVENT,
906   KEY_PRESS_EVENT,
907   KEY_RELEASE_EVENT,
908   MOTION_EVENT,
909   ENTER_EVENT,
910   LEAVE_EVENT,
911   ALLOCATION_CHANGED,
912   TRANSITIONS_COMPLETED,
913
914   LAST_SIGNAL
915 };
916
917 static guint actor_signals[LAST_SIGNAL] = { 0, };
918
919 static void clutter_container_iface_init  (ClutterContainerIface  *iface);
920 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
921 static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
922 static void atk_implementor_iface_init    (AtkImplementorIface    *iface);
923
924 /* These setters are all static for now, maybe they should be in the
925  * public API, but they are perhaps obscure enough to leave only as
926  * properties
927  */
928 static void clutter_actor_set_min_width          (ClutterActor *self,
929                                                   gfloat        min_width);
930 static void clutter_actor_set_min_height         (ClutterActor *self,
931                                                   gfloat        min_height);
932 static void clutter_actor_set_natural_width      (ClutterActor *self,
933                                                   gfloat        natural_width);
934 static void clutter_actor_set_natural_height     (ClutterActor *self,
935                                                   gfloat        natural_height);
936 static void clutter_actor_set_min_width_set      (ClutterActor *self,
937                                                   gboolean      use_min_width);
938 static void clutter_actor_set_min_height_set     (ClutterActor *self,
939                                                   gboolean      use_min_height);
940 static void clutter_actor_set_natural_width_set  (ClutterActor *self,
941                                                   gboolean  use_natural_width);
942 static void clutter_actor_set_natural_height_set (ClutterActor *self,
943                                                   gboolean  use_natural_height);
944 static void clutter_actor_update_map_state       (ClutterActor  *self,
945                                                   MapStateChange change);
946 static void clutter_actor_unrealize_not_hiding   (ClutterActor *self);
947
948 /* Helper routines for managing anchor coords */
949 static void clutter_anchor_coord_get_units (ClutterActor      *self,
950                                             const AnchorCoord *coord,
951                                             gfloat            *x,
952                                             gfloat            *y,
953                                             gfloat            *z);
954 static void clutter_anchor_coord_set_units (AnchorCoord       *coord,
955                                             gfloat             x,
956                                             gfloat             y,
957                                             gfloat             z);
958
959 static ClutterGravity clutter_anchor_coord_get_gravity (const AnchorCoord *coord);
960 static void           clutter_anchor_coord_set_gravity (AnchorCoord       *coord,
961                                                         ClutterGravity     gravity);
962
963 static gboolean clutter_anchor_coord_is_zero (const AnchorCoord *coord);
964
965 static void _clutter_actor_queue_only_relayout (ClutterActor *self);
966
967 static void _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
968                                                                ClutterActor *ancestor,
969                                                                CoglMatrix *matrix);
970
971 static ClutterPaintVolume *_clutter_actor_get_paint_volume_mutable (ClutterActor *self);
972
973 static guint8   clutter_actor_get_paint_opacity_internal        (ClutterActor *self);
974
975 static inline void clutter_actor_set_background_color_internal (ClutterActor *self,
976                                                                 const ClutterColor *color);
977
978 static void on_layout_manager_changed (ClutterLayoutManager *manager,
979                                        ClutterActor         *self);
980
981 /* Helper macro which translates by the anchor coord, applies the
982    given transformation and then translates back */
983 #define TRANSFORM_ABOUT_ANCHOR_COORD(a,m,c,_transform)  G_STMT_START { \
984   gfloat _tx, _ty, _tz;                                                \
985   clutter_anchor_coord_get_units ((a), (c), &_tx, &_ty, &_tz);         \
986   cogl_matrix_translate ((m), _tx, _ty, _tz);                          \
987   { _transform; }                                                      \
988   cogl_matrix_translate ((m), -_tx, -_ty, -_tz);        } G_STMT_END
989
990 static GQuark quark_shader_data = 0;
991 static GQuark quark_actor_layout_info = 0;
992 static GQuark quark_actor_transform_info = 0;
993 static GQuark quark_actor_animation_info = 0;
994
995 G_DEFINE_TYPE_WITH_CODE (ClutterActor,
996                          clutter_actor,
997                          G_TYPE_INITIALLY_UNOWNED,
998                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
999                                                 clutter_container_iface_init)
1000                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
1001                                                 clutter_scriptable_iface_init)
1002                          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
1003                                                 clutter_animatable_iface_init)
1004                          G_IMPLEMENT_INTERFACE (ATK_TYPE_IMPLEMENTOR,
1005                                                 atk_implementor_iface_init));
1006
1007 /*< private >
1008  * clutter_actor_get_debug_name:
1009  * @actor: a #ClutterActor
1010  *
1011  * Retrieves a printable name of @actor for debugging messages
1012  *
1013  * Return value: a string with a printable name
1014  */
1015 const gchar *
1016 _clutter_actor_get_debug_name (ClutterActor *actor)
1017 {
1018   return actor->priv->name != NULL ? actor->priv->name
1019                                    : G_OBJECT_TYPE_NAME (actor);
1020 }
1021
1022 #ifdef CLUTTER_ENABLE_DEBUG
1023 /* XXX - this is for debugging only, remove once working (or leave
1024  * in only in some debug mode). Should leave it for a little while
1025  * until we're confident in the new map/realize/visible handling.
1026  */
1027 static inline void
1028 clutter_actor_verify_map_state (ClutterActor *self)
1029 {
1030   ClutterActorPrivate *priv = self->priv;
1031
1032   if (CLUTTER_ACTOR_IS_REALIZED (self))
1033     {
1034       /* all bets are off during reparent when we're potentially realized,
1035        * but should not be according to invariants
1036        */
1037       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1038         {
1039           if (priv->parent == NULL)
1040             {
1041               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1042                 {
1043                 }
1044               else
1045                 g_warning ("Realized non-toplevel actor '%s' should "
1046                            "have a parent",
1047                            _clutter_actor_get_debug_name (self));
1048             }
1049           else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1050             {
1051               g_warning ("Realized actor %s has an unrealized parent %s",
1052                          _clutter_actor_get_debug_name (self),
1053                          _clutter_actor_get_debug_name (priv->parent));
1054             }
1055         }
1056     }
1057
1058   if (CLUTTER_ACTOR_IS_MAPPED (self))
1059     {
1060       if (!CLUTTER_ACTOR_IS_REALIZED (self))
1061         g_warning ("Actor '%s' is mapped but not realized",
1062                    _clutter_actor_get_debug_name (self));
1063
1064       /* remaining bets are off during reparent when we're potentially
1065        * mapped, but should not be according to invariants
1066        */
1067       if (!CLUTTER_ACTOR_IN_REPARENT (self))
1068         {
1069           if (priv->parent == NULL)
1070             {
1071               if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1072                 {
1073                   if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
1074                       !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1075                     {
1076                       g_warning ("Toplevel actor '%s' is mapped "
1077                                  "but not visible",
1078                                  _clutter_actor_get_debug_name (self));
1079                     }
1080                 }
1081               else
1082                 {
1083                   g_warning ("Mapped actor '%s' should have a parent",
1084                              _clutter_actor_get_debug_name (self));
1085                 }
1086             }
1087           else
1088             {
1089               ClutterActor *iter = self;
1090
1091               /* check for the enable_paint_unmapped flag on the actor
1092                * and parents; if the flag is enabled at any point of this
1093                * branch of the scene graph then all the later checks
1094                * become pointless
1095                */
1096               while (iter != NULL)
1097                 {
1098                   if (iter->priv->enable_paint_unmapped)
1099                     return;
1100
1101                   iter = iter->priv->parent;
1102                 }
1103
1104               if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
1105                 {
1106                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1107                              "is not visible",
1108                              _clutter_actor_get_debug_name (self),
1109                              _clutter_actor_get_debug_name (priv->parent));
1110                 }
1111
1112               if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1113                 {
1114                   g_warning ("Actor '%s' should not be mapped if parent '%s'"
1115                              "is not realized",
1116                              _clutter_actor_get_debug_name (self),
1117                              _clutter_actor_get_debug_name (priv->parent));
1118                 }
1119
1120               if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
1121                 {
1122                   if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
1123                     g_warning ("Actor '%s' is mapped but its non-toplevel "
1124                                "parent '%s' is not mapped",
1125                                _clutter_actor_get_debug_name (self),
1126                                _clutter_actor_get_debug_name (priv->parent));
1127                 }
1128             }
1129         }
1130     }
1131 }
1132
1133 #endif /* CLUTTER_ENABLE_DEBUG */
1134
1135 static void
1136 clutter_actor_set_mapped (ClutterActor *self,
1137                           gboolean      mapped)
1138 {
1139   if (CLUTTER_ACTOR_IS_MAPPED (self) == mapped)
1140     return;
1141
1142   if (mapped)
1143     {
1144       CLUTTER_ACTOR_GET_CLASS (self)->map (self);
1145       g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1146     }
1147   else
1148     {
1149       CLUTTER_ACTOR_GET_CLASS (self)->unmap (self);
1150       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1151     }
1152 }
1153
1154 /* this function updates the mapped and realized states according to
1155  * invariants, in the appropriate order.
1156  */
1157 static void
1158 clutter_actor_update_map_state (ClutterActor  *self,
1159                                 MapStateChange change)
1160 {
1161   gboolean was_mapped;
1162
1163   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1164
1165   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1166     {
1167       /* the mapped flag on top-level actors must be set by the
1168        * per-backend implementation because it might be asynchronous.
1169        *
1170        * That is, the MAPPED flag on toplevels currently tracks the X
1171        * server mapped-ness of the window, while the expected behavior
1172        * (if used to GTK) may be to track WM_STATE!=WithdrawnState.
1173        * This creates some weird complexity by breaking the invariant
1174        * that if we're visible and all ancestors shown then we are
1175        * also mapped - instead, we are mapped if all ancestors
1176        * _possibly excepting_ the stage are mapped. The stage
1177        * will map/unmap for example when it is minimized or
1178        * moved to another workspace.
1179        *
1180        * So, the only invariant on the stage is that if visible it
1181        * should be realized, and that it has to be visible to be
1182        * mapped.
1183        */
1184       if (CLUTTER_ACTOR_IS_VISIBLE (self))
1185         clutter_actor_realize (self);
1186
1187       switch (change)
1188         {
1189         case MAP_STATE_CHECK:
1190           break;
1191
1192         case MAP_STATE_MAKE_MAPPED:
1193           g_assert (!was_mapped);
1194           clutter_actor_set_mapped (self, TRUE);
1195           break;
1196
1197         case MAP_STATE_MAKE_UNMAPPED:
1198           g_assert (was_mapped);
1199           clutter_actor_set_mapped (self, FALSE);
1200           break;
1201
1202         case MAP_STATE_MAKE_UNREALIZED:
1203           /* we only use MAKE_UNREALIZED in unparent,
1204            * and unparenting a stage isn't possible.
1205            * If someone wants to just unrealize a stage
1206            * then clutter_actor_unrealize() doesn't
1207            * go through this codepath.
1208            */
1209           g_warning ("Trying to force unrealize stage is not allowed");
1210           break;
1211         }
1212
1213       if (CLUTTER_ACTOR_IS_MAPPED (self) &&
1214           !CLUTTER_ACTOR_IS_VISIBLE (self) &&
1215           !CLUTTER_ACTOR_IN_DESTRUCTION (self))
1216         {
1217           g_warning ("Clutter toplevel of type '%s' is not visible, but "
1218                      "it is somehow still mapped",
1219                      _clutter_actor_get_debug_name (self));
1220         }
1221     }
1222   else
1223     {
1224       ClutterActorPrivate *priv = self->priv;
1225       ClutterActor *parent = priv->parent;
1226       gboolean should_be_mapped;
1227       gboolean may_be_realized;
1228       gboolean must_be_realized;
1229
1230       should_be_mapped = FALSE;
1231       may_be_realized = TRUE;
1232       must_be_realized = FALSE;
1233
1234       if (parent == NULL || change == MAP_STATE_MAKE_UNREALIZED)
1235         {
1236           may_be_realized = FALSE;
1237         }
1238       else
1239         {
1240           /* Maintain invariant that if parent is mapped, and we are
1241            * visible, then we are mapped ...  unless parent is a
1242            * stage, in which case we map regardless of parent's map
1243            * state but do require stage to be visible and realized.
1244            *
1245            * If parent is realized, that does not force us to be
1246            * realized; but if parent is unrealized, that does force
1247            * us to be unrealized.
1248            *
1249            * The reason we don't force children to realize with
1250            * parents is _clutter_actor_rerealize(); if we require that
1251            * a realized parent means children are realized, then to
1252            * unrealize an actor we would have to unrealize its
1253            * parents, which would end up meaning unrealizing and
1254            * hiding the entire stage. So we allow unrealizing a
1255            * child (as long as that child is not mapped) while that
1256            * child still has a realized parent.
1257            *
1258            * Also, if we unrealize from leaf nodes to root, and
1259            * realize from root to leaf, the invariants are never
1260            * violated if we allow children to be unrealized
1261            * while parents are realized.
1262            *
1263            * When unmapping, MAP_STATE_MAKE_UNMAPPED is specified
1264            * to force us to unmap, even though parent is still
1265            * mapped. This is because we're unmapping from leaf nodes
1266            * up to root nodes.
1267            */
1268           if (CLUTTER_ACTOR_IS_VISIBLE (self) &&
1269               change != MAP_STATE_MAKE_UNMAPPED)
1270             {
1271               gboolean parent_is_visible_realized_toplevel;
1272
1273               parent_is_visible_realized_toplevel =
1274                 (CLUTTER_ACTOR_IS_TOPLEVEL (parent) &&
1275                  CLUTTER_ACTOR_IS_VISIBLE (parent) &&
1276                  CLUTTER_ACTOR_IS_REALIZED (parent));
1277
1278               if (CLUTTER_ACTOR_IS_MAPPED (parent) ||
1279                   parent_is_visible_realized_toplevel)
1280                 {
1281                   must_be_realized = TRUE;
1282                   should_be_mapped = TRUE;
1283                 }
1284             }
1285
1286           /* if the actor has been set to be painted even if unmapped
1287            * then we should map it and check for realization as well;
1288            * this is an override for the branch of the scene graph
1289            * which begins with this node
1290            */
1291           if (priv->enable_paint_unmapped)
1292             {
1293               if (priv->parent == NULL)
1294                 g_warning ("Attempting to map an unparented actor '%s'",
1295                            _clutter_actor_get_debug_name (self));
1296
1297               should_be_mapped = TRUE;
1298               must_be_realized = TRUE;
1299             }
1300
1301           if (!CLUTTER_ACTOR_IS_REALIZED (parent))
1302             may_be_realized = FALSE;
1303         }
1304
1305       if (change == MAP_STATE_MAKE_MAPPED && !should_be_mapped)
1306         {
1307           if (parent == NULL)
1308             g_warning ("Attempting to map a child that does not "
1309                        "meet the necessary invariants: the actor '%s' "
1310                        "has no parent",
1311                        _clutter_actor_get_debug_name (self));
1312           else
1313             g_warning ("Attempting to map a child that does not "
1314                        "meet the necessary invariants: the actor '%s' "
1315                        "is parented to an unmapped actor '%s'",
1316                        _clutter_actor_get_debug_name (self),
1317                        _clutter_actor_get_debug_name (priv->parent));
1318         }
1319
1320       /* If in reparent, we temporarily suspend unmap and unrealize.
1321        *
1322        * We want to go in the order "realize, map" and "unmap, unrealize"
1323        */
1324
1325       /* Unmap */
1326       if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
1327         clutter_actor_set_mapped (self, FALSE);
1328
1329       /* Realize */
1330       if (must_be_realized)
1331         clutter_actor_realize (self);
1332
1333       /* if we must be realized then we may be, presumably */
1334       g_assert (!(must_be_realized && !may_be_realized));
1335
1336       /* Unrealize */
1337       if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
1338         clutter_actor_unrealize_not_hiding (self);
1339
1340       /* Map */
1341       if (should_be_mapped)
1342         {
1343           if (!must_be_realized)
1344             g_warning ("Somehow we think actor '%s' should be mapped but "
1345                        "not realized, which isn't allowed",
1346                        _clutter_actor_get_debug_name (self));
1347
1348           /* realization is allowed to fail (though I don't know what
1349            * an app is supposed to do about that - shouldn't it just
1350            * be a g_error? anyway, we have to avoid mapping if this
1351            * happens)
1352            */
1353           if (CLUTTER_ACTOR_IS_REALIZED (self))
1354             clutter_actor_set_mapped (self, TRUE);
1355         }
1356     }
1357
1358 #ifdef CLUTTER_ENABLE_DEBUG
1359   /* check all invariants were kept */
1360   clutter_actor_verify_map_state (self);
1361 #endif
1362 }
1363
1364 static void
1365 clutter_actor_real_map (ClutterActor *self)
1366 {
1367   ClutterActorPrivate *priv = self->priv;
1368   ClutterActor *stage, *iter;
1369
1370   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1371
1372   CLUTTER_NOTE (ACTOR, "Mapping actor '%s'",
1373                 _clutter_actor_get_debug_name (self));
1374
1375   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1376
1377   stage = _clutter_actor_get_stage_internal (self);
1378   priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
1379
1380   CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
1381                 priv->pick_id,
1382                 _clutter_actor_get_debug_name (self));
1383
1384   /* notify on parent mapped before potentially mapping
1385    * children, so apps see a top-down notification.
1386    */
1387   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1388
1389   for (iter = self->priv->first_child;
1390        iter != NULL;
1391        iter = iter->priv->next_sibling)
1392     {
1393       clutter_actor_map (iter);
1394     }
1395 }
1396
1397 /**
1398  * clutter_actor_map:
1399  * @self: A #ClutterActor
1400  *
1401  * Sets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly maps
1402  * and realizes its children if they are visible. Does nothing if the
1403  * actor is not visible.
1404  *
1405  * Calling this function is strongly disencouraged: the default
1406  * implementation of #ClutterActorClass.map() will map all the children
1407  * of an actor when mapping its parent.
1408  *
1409  * When overriding map, it is mandatory to chain up to the parent
1410  * implementation.
1411  *
1412  * Since: 1.0
1413  */
1414 void
1415 clutter_actor_map (ClutterActor *self)
1416 {
1417   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1418
1419   if (CLUTTER_ACTOR_IS_MAPPED (self))
1420     return;
1421
1422   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1423     return;
1424
1425   clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
1426 }
1427
1428 static void
1429 clutter_actor_real_unmap (ClutterActor *self)
1430 {
1431   ClutterActorPrivate *priv = self->priv;
1432   ClutterActor *iter;
1433
1434   g_assert (CLUTTER_ACTOR_IS_MAPPED (self));
1435
1436   CLUTTER_NOTE (ACTOR, "Unmapping actor '%s'",
1437                 _clutter_actor_get_debug_name (self));
1438
1439   for (iter = self->priv->first_child;
1440        iter != NULL;
1441        iter = iter->priv->next_sibling)
1442     {
1443       clutter_actor_unmap (iter);
1444     }
1445
1446   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
1447
1448   /* clear the contents of the last paint volume, so that hiding + moving +
1449    * showing will not result in the wrong area being repainted
1450    */
1451   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
1452   priv->last_paint_volume_valid = TRUE;
1453
1454   /* notify on parent mapped after potentially unmapping
1455    * children, so apps see a bottom-up notification.
1456    */
1457   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MAPPED]);
1458
1459   /* relinquish keyboard focus if we were unmapped while owning it */
1460   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
1461     {
1462       ClutterStage *stage;
1463
1464       stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
1465
1466       if (stage != NULL)
1467         _clutter_stage_release_pick_id (stage, priv->pick_id);
1468
1469       priv->pick_id = -1;
1470
1471       if (stage != NULL &&
1472           clutter_stage_get_key_focus (stage) == self)
1473         {
1474           clutter_stage_set_key_focus (stage, NULL);
1475         }
1476     }
1477 }
1478
1479 /**
1480  * clutter_actor_unmap:
1481  * @self: A #ClutterActor
1482  *
1483  * Unsets the %CLUTTER_ACTOR_MAPPED flag on the actor and possibly
1484  * unmaps its children if they were mapped.
1485  *
1486  * Calling this function is not encouraged: the default #ClutterActor
1487  * implementation of #ClutterActorClass.unmap() will also unmap any
1488  * eventual children by default when their parent is unmapped.
1489  *
1490  * When overriding #ClutterActorClass.unmap(), it is mandatory to
1491  * chain up to the parent implementation.
1492  *
1493  * <note>It is important to note that the implementation of the
1494  * #ClutterActorClass.unmap() virtual function may be called after
1495  * the #ClutterActorClass.destroy() or the #GObjectClass.dispose()
1496  * implementation, but it is guaranteed to be called before the
1497  * #GObjectClass.finalize() implementation.</note>
1498  *
1499  * Since: 1.0
1500  */
1501 void
1502 clutter_actor_unmap (ClutterActor *self)
1503 {
1504   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1505
1506   if (!CLUTTER_ACTOR_IS_MAPPED (self))
1507     return;
1508
1509   clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
1510 }
1511
1512 static void
1513 clutter_actor_real_show (ClutterActor *self)
1514 {
1515   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1516     {
1517       ClutterActorPrivate *priv = self->priv;
1518
1519       CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1520
1521       /* we notify on the "visible" flag in the clutter_actor_show()
1522        * wrapper so the entire show signal emission completes first
1523        * (?)
1524        */
1525       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1526
1527       /* we queue a relayout unless the actor is inside a
1528        * container that explicitly told us not to
1529        */
1530       if (priv->parent != NULL &&
1531           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1532         {
1533           /* While an actor is hidden the parent may not have
1534            * allocated/requested so we need to start from scratch
1535            * and avoid the short-circuiting in
1536            * clutter_actor_queue_relayout().
1537            */
1538           priv->needs_width_request  = FALSE;
1539           priv->needs_height_request = FALSE;
1540           priv->needs_allocation     = FALSE;
1541           clutter_actor_queue_relayout (self);
1542         }
1543     }
1544 }
1545
1546 static inline void
1547 set_show_on_set_parent (ClutterActor *self,
1548                         gboolean      set_show)
1549 {
1550   ClutterActorPrivate *priv = self->priv;
1551
1552   set_show = !!set_show;
1553
1554   if (priv->show_on_set_parent == set_show)
1555     return;
1556
1557   if (priv->parent == NULL)
1558     {
1559       priv->show_on_set_parent = set_show;
1560       g_object_notify_by_pspec (G_OBJECT (self),
1561                                 obj_props[PROP_SHOW_ON_SET_PARENT]);
1562     }
1563 }
1564
1565 /**
1566  * clutter_actor_show:
1567  * @self: A #ClutterActor
1568  *
1569  * Flags an actor to be displayed. An actor that isn't shown will not
1570  * be rendered on the stage.
1571  *
1572  * Actors are visible by default.
1573  *
1574  * If this function is called on an actor without a parent, the
1575  * #ClutterActor:show-on-set-parent will be set to %TRUE as a side
1576  * effect.
1577  */
1578 void
1579 clutter_actor_show (ClutterActor *self)
1580 {
1581   ClutterActorPrivate *priv;
1582
1583   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1584
1585   /* simple optimization */
1586   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1587     {
1588       /* we still need to set the :show-on-set-parent property, in
1589        * case show() is called on an unparented actor
1590        */
1591       set_show_on_set_parent (self, TRUE);
1592       return;
1593     }
1594
1595 #ifdef CLUTTER_ENABLE_DEBUG
1596   clutter_actor_verify_map_state (self);
1597 #endif
1598
1599   priv = self->priv;
1600
1601   g_object_freeze_notify (G_OBJECT (self));
1602
1603   set_show_on_set_parent (self, TRUE);
1604
1605   g_signal_emit (self, actor_signals[SHOW], 0);
1606   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1607
1608   if (priv->parent != NULL)
1609     clutter_actor_queue_redraw (priv->parent);
1610
1611   g_object_thaw_notify (G_OBJECT (self));
1612 }
1613
1614 /**
1615  * clutter_actor_show_all:
1616  * @self: a #ClutterActor
1617  *
1618  * Calls clutter_actor_show() on all children of an actor (if any).
1619  *
1620  * Since: 0.2
1621  *
1622  * Deprecated: 1.10: Actors are visible by default
1623  */
1624 void
1625 clutter_actor_show_all (ClutterActor *self)
1626 {
1627   ClutterActorClass *klass;
1628
1629   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1630
1631   klass = CLUTTER_ACTOR_GET_CLASS (self);
1632   if (klass->show_all)
1633     klass->show_all (self);
1634 }
1635
1636 static void
1637 clutter_actor_real_hide (ClutterActor *self)
1638 {
1639   if (CLUTTER_ACTOR_IS_VISIBLE (self))
1640     {
1641       ClutterActorPrivate *priv = self->priv;
1642
1643       CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_VISIBLE);
1644
1645       /* we notify on the "visible" flag in the clutter_actor_hide()
1646        * wrapper so the entire hide signal emission completes first
1647        * (?)
1648        */
1649       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1650
1651       /* we queue a relayout unless the actor is inside a
1652        * container that explicitly told us not to
1653        */
1654       if (priv->parent != NULL &&
1655           (!(priv->parent->flags & CLUTTER_ACTOR_NO_LAYOUT)))
1656         clutter_actor_queue_relayout (priv->parent);
1657     }
1658 }
1659
1660 /**
1661  * clutter_actor_hide:
1662  * @self: A #ClutterActor
1663  *
1664  * Flags an actor to be hidden. A hidden actor will not be
1665  * rendered on the stage.
1666  *
1667  * Actors are visible by default.
1668  *
1669  * If this function is called on an actor without a parent, the
1670  * #ClutterActor:show-on-set-parent property will be set to %FALSE
1671  * as a side-effect.
1672  */
1673 void
1674 clutter_actor_hide (ClutterActor *self)
1675 {
1676   ClutterActorPrivate *priv;
1677
1678   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1679
1680   /* simple optimization */
1681   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
1682     {
1683       /* we still need to set the :show-on-set-parent property, in
1684        * case hide() is called on an unparented actor
1685        */
1686       set_show_on_set_parent (self, FALSE);
1687       return;
1688     }
1689
1690 #ifdef CLUTTER_ENABLE_DEBUG
1691   clutter_actor_verify_map_state (self);
1692 #endif
1693
1694   priv = self->priv;
1695
1696   g_object_freeze_notify (G_OBJECT (self));
1697
1698   set_show_on_set_parent (self, FALSE);
1699
1700   g_signal_emit (self, actor_signals[HIDE], 0);
1701   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_VISIBLE]);
1702
1703   if (priv->parent != NULL)
1704     clutter_actor_queue_redraw (priv->parent);
1705
1706   g_object_thaw_notify (G_OBJECT (self));
1707 }
1708
1709 /**
1710  * clutter_actor_hide_all:
1711  * @self: a #ClutterActor
1712  *
1713  * Calls clutter_actor_hide() on all child actors (if any).
1714  *
1715  * Since: 0.2
1716  *
1717  * Deprecated: 1.10: Using clutter_actor_hide() on the actor will
1718  *   prevent its children from being painted as well.
1719  */
1720 void
1721 clutter_actor_hide_all (ClutterActor *self)
1722 {
1723   ClutterActorClass *klass;
1724
1725   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1726
1727   klass = CLUTTER_ACTOR_GET_CLASS (self);
1728   if (klass->hide_all)
1729     klass->hide_all (self);
1730 }
1731
1732 /**
1733  * clutter_actor_realize:
1734  * @self: A #ClutterActor
1735  *
1736  * Realization informs the actor that it is attached to a stage. It
1737  * can use this to allocate resources if it wanted to delay allocation
1738  * until it would be rendered. However it is perfectly acceptable for
1739  * an actor to create resources before being realized because Clutter
1740  * only ever has a single rendering context so that actor is free to
1741  * be moved from one stage to another.
1742  *
1743  * This function does nothing if the actor is already realized.
1744  *
1745  * Because a realized actor must have realized parent actors, calling
1746  * clutter_actor_realize() will also realize all parents of the actor.
1747  *
1748  * This function does not realize child actors, except in the special
1749  * case that realizing the stage, when the stage is visible, will
1750  * suddenly map (and thus realize) the children of the stage.
1751  **/
1752 void
1753 clutter_actor_realize (ClutterActor *self)
1754 {
1755   ClutterActorPrivate *priv;
1756
1757   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1758
1759   priv = self->priv;
1760
1761 #ifdef CLUTTER_ENABLE_DEBUG
1762   clutter_actor_verify_map_state (self);
1763 #endif
1764
1765   if (CLUTTER_ACTOR_IS_REALIZED (self))
1766     return;
1767
1768   /* To be realized, our parent actors must be realized first.
1769    * This will only succeed if we're inside a toplevel.
1770    */
1771   if (priv->parent != NULL)
1772     clutter_actor_realize (priv->parent);
1773
1774   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
1775     {
1776       /* toplevels can be realized at any time */
1777     }
1778   else
1779     {
1780       /* "Fail" the realization if parent is missing or unrealized;
1781        * this should really be a g_warning() not some kind of runtime
1782        * failure; how can an app possibly recover? Instead it's a bug
1783        * in the app and the app should get an explanatory warning so
1784        * someone can fix it. But for now it's too hard to fix this
1785        * because e.g. ClutterTexture needs reworking.
1786        */
1787       if (priv->parent == NULL ||
1788           !CLUTTER_ACTOR_IS_REALIZED (priv->parent))
1789         return;
1790     }
1791
1792   CLUTTER_NOTE (ACTOR, "Realizing actor '%s'", _clutter_actor_get_debug_name (self));
1793
1794   CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1795   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1796
1797   g_signal_emit (self, actor_signals[REALIZE], 0);
1798
1799   /* Stage actor is allowed to unset the realized flag again in its
1800    * default signal handler, though that is a pathological situation.
1801    */
1802
1803   /* If realization "failed" we'll have to update child state. */
1804   clutter_actor_update_map_state (self, MAP_STATE_CHECK);
1805 }
1806
1807 static void
1808 clutter_actor_real_unrealize (ClutterActor *self)
1809 {
1810   /* we must be unmapped (implying our children are also unmapped) */
1811   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1812 }
1813
1814 /**
1815  * clutter_actor_unrealize:
1816  * @self: A #ClutterActor
1817  *
1818  * Unrealization informs the actor that it may be being destroyed or
1819  * moved to another stage. The actor may want to destroy any
1820  * underlying graphics resources at this point. However it is
1821  * perfectly acceptable for it to retain the resources until the actor
1822  * is destroyed because Clutter only ever uses a single rendering
1823  * context and all of the graphics resources are valid on any stage.
1824  *
1825  * Because mapped actors must be realized, actors may not be
1826  * unrealized if they are mapped. This function hides the actor to be
1827  * sure it isn't mapped, an application-visible side effect that you
1828  * may not be expecting.
1829  *
1830  * This function should not be called by application code.
1831  */
1832 void
1833 clutter_actor_unrealize (ClutterActor *self)
1834 {
1835   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1836   g_return_if_fail (!CLUTTER_ACTOR_IS_MAPPED (self));
1837
1838 /* This function should not really be in the public API, because
1839  * there isn't a good reason to call it. ClutterActor will already
1840  * unrealize things for you when it's important to do so.
1841  *
1842  * If you were using clutter_actor_unrealize() in a dispose
1843  * implementation, then don't, just chain up to ClutterActor's
1844  * dispose.
1845  *
1846  * If you were using clutter_actor_unrealize() to implement
1847  * unrealizing children of your container, then don't, ClutterActor
1848  * will already take care of that.
1849  *
1850  * If you were using clutter_actor_unrealize() to re-realize to
1851  * create your resources in a different way, then use
1852  * _clutter_actor_rerealize() (inside Clutter) or just call your
1853  * code that recreates your resources directly (outside Clutter).
1854  */
1855
1856 #ifdef CLUTTER_ENABLE_DEBUG
1857   clutter_actor_verify_map_state (self);
1858 #endif
1859
1860   clutter_actor_hide (self);
1861
1862   clutter_actor_unrealize_not_hiding (self);
1863 }
1864
1865 static ClutterActorTraverseVisitFlags
1866 unrealize_actor_before_children_cb (ClutterActor *self,
1867                                     int depth,
1868                                     void *user_data)
1869 {
1870   /* If an actor is already unrealized we know its children have also
1871    * already been unrealized... */
1872   if (!CLUTTER_ACTOR_IS_REALIZED (self))
1873     return CLUTTER_ACTOR_TRAVERSE_VISIT_SKIP_CHILDREN;
1874
1875   g_signal_emit (self, actor_signals[UNREALIZE], 0);
1876
1877   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1878 }
1879
1880 static ClutterActorTraverseVisitFlags
1881 unrealize_actor_after_children_cb (ClutterActor *self,
1882                                    int depth,
1883                                    void *user_data)
1884 {
1885   /* We want to unset the realized flag only _after_
1886    * child actors are unrealized, to maintain invariants.
1887    */
1888   CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
1889   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REALIZED]);
1890   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
1891 }
1892
1893 /*
1894  * clutter_actor_unrealize_not_hiding:
1895  * @self: A #ClutterActor
1896  *
1897  * Unrealization informs the actor that it may be being destroyed or
1898  * moved to another stage. The actor may want to destroy any
1899  * underlying graphics resources at this point. However it is
1900  * perfectly acceptable for it to retain the resources until the actor
1901  * is destroyed because Clutter only ever uses a single rendering
1902  * context and all of the graphics resources are valid on any stage.
1903  *
1904  * Because mapped actors must be realized, actors may not be
1905  * unrealized if they are mapped. You must hide the actor or one of
1906  * its parents before attempting to unrealize.
1907  *
1908  * This function is separate from clutter_actor_unrealize() because it
1909  * does not automatically hide the actor.
1910  * Actors need not be hidden to be unrealized, they just need to
1911  * be unmapped. In fact we don't want to mess up the application's
1912  * setting of the "visible" flag, so hiding is very undesirable.
1913  *
1914  * clutter_actor_unrealize() does a clutter_actor_hide() just for
1915  * backward compatibility.
1916  */
1917 static void
1918 clutter_actor_unrealize_not_hiding (ClutterActor *self)
1919 {
1920   _clutter_actor_traverse (self,
1921                            CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
1922                            unrealize_actor_before_children_cb,
1923                            unrealize_actor_after_children_cb,
1924                            NULL);
1925 }
1926
1927 /*
1928  * _clutter_actor_rerealize:
1929  * @self: A #ClutterActor
1930  * @callback: Function to call while unrealized
1931  * @data: data for callback
1932  *
1933  * If an actor is already unrealized, this just calls the callback.
1934  *
1935  * If it is realized, it unrealizes temporarily, calls the callback,
1936  * and then re-realizes the actor.
1937  *
1938  * As a side effect, leaves all children of the actor unrealized if
1939  * the actor was realized but not showing.  This is because when we
1940  * unrealize the actor temporarily we must unrealize its children
1941  * (e.g. children of a stage can't be realized if stage window is
1942  * gone). And we aren't clever enough to save the realization state of
1943  * all children. In most cases this should not matter, because
1944  * the children will automatically realize when they next become mapped.
1945  */
1946 void
1947 _clutter_actor_rerealize (ClutterActor    *self,
1948                           ClutterCallback  callback,
1949                           void            *data)
1950 {
1951   gboolean was_mapped;
1952   gboolean was_showing;
1953   gboolean was_realized;
1954
1955   g_return_if_fail (CLUTTER_IS_ACTOR (self));
1956
1957 #ifdef CLUTTER_ENABLE_DEBUG
1958   clutter_actor_verify_map_state (self);
1959 #endif
1960
1961   was_realized = CLUTTER_ACTOR_IS_REALIZED (self);
1962   was_mapped = CLUTTER_ACTOR_IS_MAPPED (self);
1963   was_showing = CLUTTER_ACTOR_IS_VISIBLE (self);
1964
1965   /* Must be unmapped to unrealize. Note we only have to hide this
1966    * actor if it was mapped (if all parents were showing).  If actor
1967    * is merely visible (but not mapped), then that's fine, we can
1968    * leave it visible.
1969    */
1970   if (was_mapped)
1971     clutter_actor_hide (self);
1972
1973   g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
1974
1975   /* unrealize self and all children */
1976   clutter_actor_unrealize_not_hiding (self);
1977
1978   if (callback != NULL)
1979     {
1980       (* callback) (self, data);
1981     }
1982
1983   if (was_showing)
1984     clutter_actor_show (self); /* will realize only if mapping implies it */
1985   else if (was_realized)
1986     clutter_actor_realize (self); /* realize self and all parents */
1987 }
1988
1989 static void
1990 clutter_actor_real_pick (ClutterActor       *self,
1991                          const ClutterColor *color)
1992 {
1993   /* the default implementation is just to paint a rectangle
1994    * with the same size of the actor using the passed color
1995    */
1996   if (clutter_actor_should_pick_paint (self))
1997     {
1998       ClutterActorBox box = { 0, };
1999       float width, height;
2000
2001       clutter_actor_get_allocation_box (self, &box);
2002
2003       width = box.x2 - box.x1;
2004       height = box.y2 - box.y1;
2005
2006       cogl_set_source_color4ub (color->red,
2007                                 color->green,
2008                                 color->blue,
2009                                 color->alpha);
2010
2011       cogl_rectangle (0, 0, width, height);
2012     }
2013
2014   /* XXX - this thoroughly sucks, but we need to maintain compatibility
2015    * with existing container classes that override the pick() virtual
2016    * and chain up to the default implementation - otherwise we'll end up
2017    * painting our children twice.
2018    *
2019    * this has to go away for 2.0; hopefully along the pick() itself.
2020    */
2021   if (CLUTTER_ACTOR_GET_CLASS (self)->pick == clutter_actor_real_pick)
2022     {
2023       ClutterActor *iter;
2024
2025       for (iter = self->priv->first_child;
2026            iter != NULL;
2027            iter = iter->priv->next_sibling)
2028         clutter_actor_paint (iter);
2029     }
2030 }
2031
2032 /**
2033  * clutter_actor_should_pick_paint:
2034  * @self: A #ClutterActor
2035  *
2036  * Should be called inside the implementation of the
2037  * #ClutterActor::pick virtual function in order to check whether
2038  * the actor should paint itself in pick mode or not.
2039  *
2040  * This function should never be called directly by applications.
2041  *
2042  * Return value: %TRUE if the actor should paint its silhouette,
2043  *   %FALSE otherwise
2044  */
2045 gboolean
2046 clutter_actor_should_pick_paint (ClutterActor *self)
2047 {
2048   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2049
2050   if (CLUTTER_ACTOR_IS_MAPPED (self) &&
2051       (_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
2052        CLUTTER_ACTOR_IS_REACTIVE (self)))
2053     return TRUE;
2054
2055   return FALSE;
2056 }
2057
2058 static void
2059 clutter_actor_real_get_preferred_width (ClutterActor *self,
2060                                         gfloat        for_height,
2061                                         gfloat       *min_width_p,
2062                                         gfloat       *natural_width_p)
2063 {
2064   ClutterActorPrivate *priv = self->priv;
2065
2066   if (priv->n_children != 0 &&
2067       priv->layout_manager != NULL)
2068     {
2069       ClutterContainer *container = CLUTTER_CONTAINER (self);
2070
2071       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2072                     "for the preferred width",
2073                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2074                     priv->layout_manager);
2075
2076       clutter_layout_manager_get_preferred_width (priv->layout_manager,
2077                                                   container,
2078                                                   for_height,
2079                                                   min_width_p,
2080                                                   natural_width_p);
2081
2082       return;
2083     }
2084
2085   /* Default implementation is always 0x0, usually an actor
2086    * using this default is relying on someone to set the
2087    * request manually
2088    */
2089   CLUTTER_NOTE (LAYOUT, "Default preferred width: 0, 0");
2090
2091   if (min_width_p)
2092     *min_width_p = 0;
2093
2094   if (natural_width_p)
2095     *natural_width_p = 0;
2096 }
2097
2098 static void
2099 clutter_actor_real_get_preferred_height (ClutterActor *self,
2100                                          gfloat        for_width,
2101                                          gfloat       *min_height_p,
2102                                          gfloat       *natural_height_p)
2103 {
2104   ClutterActorPrivate *priv = self->priv;
2105
2106   if (priv->n_children != 0 &&
2107       priv->layout_manager != NULL)
2108     {
2109       ClutterContainer *container = CLUTTER_CONTAINER (self);
2110
2111       CLUTTER_NOTE (LAYOUT, "Querying the layout manager '%s'[%p] "
2112                     "for the preferred height",
2113                     G_OBJECT_TYPE_NAME (priv->layout_manager),
2114                     priv->layout_manager);
2115
2116       clutter_layout_manager_get_preferred_height (priv->layout_manager,
2117                                                    container,
2118                                                    for_width,
2119                                                    min_height_p,
2120                                                    natural_height_p);
2121
2122       return;
2123     }
2124   /* Default implementation is always 0x0, usually an actor
2125    * using this default is relying on someone to set the
2126    * request manually
2127    */
2128   CLUTTER_NOTE (LAYOUT, "Default preferred height: 0, 0");
2129
2130   if (min_height_p)
2131     *min_height_p = 0;
2132
2133   if (natural_height_p)
2134     *natural_height_p = 0;
2135 }
2136
2137 static void
2138 clutter_actor_store_old_geometry (ClutterActor    *self,
2139                                   ClutterActorBox *box)
2140 {
2141   *box = self->priv->allocation;
2142 }
2143
2144 static inline void
2145 clutter_actor_notify_if_geometry_changed (ClutterActor          *self,
2146                                           const ClutterActorBox *old)
2147 {
2148   ClutterActorPrivate *priv = self->priv;
2149   GObject *obj = G_OBJECT (self);
2150
2151   g_object_freeze_notify (obj);
2152
2153   /* to avoid excessive requisition or allocation cycles we
2154    * use the cached values.
2155    *
2156    * - if we don't have an allocation we assume that we need
2157    *   to notify anyway
2158    * - if we don't have a width or a height request we notify
2159    *   width and height
2160    * - if we have a valid allocation then we check the old
2161    *   bounding box with the current allocation and we notify
2162    *   the changes
2163    */
2164   if (priv->needs_allocation)
2165     {
2166       g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2167       g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2168       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2169       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2170     }
2171   else if (priv->needs_width_request || priv->needs_height_request)
2172     {
2173       g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2174       g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2175     }
2176   else
2177     {
2178       gfloat x, y;
2179       gfloat width, height;
2180
2181       x = priv->allocation.x1;
2182       y = priv->allocation.y1;
2183       width = priv->allocation.x2 - priv->allocation.x1;
2184       height = priv->allocation.y2 - priv->allocation.y1;
2185
2186       if (x != old->x1)
2187         g_object_notify_by_pspec (obj, obj_props[PROP_X]);
2188
2189       if (y != old->y1)
2190         g_object_notify_by_pspec (obj, obj_props[PROP_Y]);
2191
2192       if (width != (old->x2 - old->x1))
2193         g_object_notify_by_pspec (obj, obj_props[PROP_WIDTH]);
2194
2195       if (height != (old->y2 - old->y1))
2196         g_object_notify_by_pspec (obj, obj_props[PROP_HEIGHT]);
2197     }
2198
2199   g_object_thaw_notify (obj);
2200 }
2201
2202 /*< private >
2203  * clutter_actor_set_allocation_internal:
2204  * @self: a #ClutterActor
2205  * @box: a #ClutterActorBox
2206  * @flags: allocation flags
2207  *
2208  * Stores the allocation of @self.
2209  *
2210  * This function only performs basic storage and property notification.
2211  *
2212  * This function should be called by clutter_actor_set_allocation()
2213  * and by the default implementation of #ClutterActorClass.allocate().
2214  *
2215  * Return value: %TRUE if the allocation of the #ClutterActor has been
2216  *   changed, and %FALSE otherwise
2217  */
2218 static inline gboolean
2219 clutter_actor_set_allocation_internal (ClutterActor           *self,
2220                                        const ClutterActorBox  *box,
2221                                        ClutterAllocationFlags  flags)
2222 {
2223   ClutterActorPrivate *priv = self->priv;
2224   GObject *obj;
2225   gboolean x1_changed, y1_changed, x2_changed, y2_changed;
2226   gboolean flags_changed;
2227   gboolean retval;
2228   ClutterActorBox old_alloc = { 0, };
2229
2230   obj = G_OBJECT (self);
2231
2232   g_object_freeze_notify (obj);
2233
2234   clutter_actor_store_old_geometry (self, &old_alloc);
2235
2236   x1_changed = priv->allocation.x1 != box->x1;
2237   y1_changed = priv->allocation.y1 != box->y1;
2238   x2_changed = priv->allocation.x2 != box->x2;
2239   y2_changed = priv->allocation.y2 != box->y2;
2240
2241   flags_changed = priv->allocation_flags != flags;
2242
2243   priv->allocation = *box;
2244   priv->allocation_flags = flags;
2245
2246   /* allocation is authoritative */
2247   priv->needs_width_request = FALSE;
2248   priv->needs_height_request = FALSE;
2249   priv->needs_allocation = FALSE;
2250
2251   if (x1_changed || y1_changed ||
2252       x2_changed || y2_changed ||
2253       flags_changed)
2254     {
2255       CLUTTER_NOTE (LAYOUT, "Allocation for '%s' changed",
2256                     _clutter_actor_get_debug_name (self));
2257
2258       priv->transform_valid = FALSE;
2259
2260       g_object_notify_by_pspec (obj, obj_props[PROP_ALLOCATION]);
2261
2262       /* if the allocation changes, so does the content box */
2263       if (priv->content != NULL)
2264         {
2265           priv->content_box_valid = FALSE;
2266           g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
2267         }
2268
2269       retval = TRUE;
2270     }
2271   else
2272     retval = FALSE;
2273
2274   clutter_actor_notify_if_geometry_changed (self, &old_alloc);
2275
2276   g_object_thaw_notify (obj);
2277
2278   return retval;
2279 }
2280
2281 static void clutter_actor_real_allocate (ClutterActor           *self,
2282                                          const ClutterActorBox  *box,
2283                                          ClutterAllocationFlags  flags);
2284
2285 static inline void
2286 clutter_actor_maybe_layout_children (ClutterActor           *self,
2287                                      const ClutterActorBox  *allocation,
2288                                      ClutterAllocationFlags  flags)
2289 {
2290   ClutterActorPrivate *priv = self->priv;
2291
2292   /* this is going to be a bit hard to follow, so let's put an explanation
2293    * here.
2294    *
2295    * we want ClutterActor to have a default layout manager if the actor was
2296    * created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
2297    *
2298    * we also want any subclass of ClutterActor that does not override the
2299    * ::allocate() virtual function to delegate to a layout manager.
2300    *
2301    * finally, we want to allow people subclassing ClutterActor and overriding
2302    * the ::allocate() vfunc to let Clutter delegate to the layout manager.
2303    *
2304    * on the other hand, we want existing actor subclasses overriding the
2305    * ::allocate() virtual function and chaining up to the parent's
2306    * implementation to continue working without allocating their children
2307    * twice, or without entering an allocation loop.
2308    *
2309    * for the first two points, we check if the class of the actor is
2310    * overridding the ::allocate() virtual function; if it isn't, then we
2311    * follow through with checking whether we have children and a layout
2312    * manager, and eventually calling clutter_layout_manager_allocate().
2313    *
2314    * for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
2315    * allocation flags that we got passed, and if it is present, we continue
2316    * with the check above.
2317    *
2318    * if neither of these two checks yields a positive result, we just
2319    * assume that the ::allocate() virtual function that resulted in this
2320    * function being called will also allocate the children of the actor.
2321    */
2322
2323   if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
2324     goto check_layout;
2325
2326   if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
2327     goto check_layout;
2328
2329   return;
2330
2331 check_layout:
2332   if (priv->n_children != 0 &&
2333       priv->layout_manager != NULL)
2334     {
2335       ClutterContainer *container = CLUTTER_CONTAINER (self);
2336       ClutterAllocationFlags children_flags;
2337       ClutterActorBox children_box;
2338
2339       /* normalize the box passed to the layout manager */
2340       children_box.x1 = children_box.y1 = 0.f;
2341       children_box.x2 = (allocation->x2 - allocation->x1);
2342       children_box.y2 = (allocation->y2 - allocation->y1);
2343
2344       /* remove the DELEGATE_LAYOUT flag; this won't be passed to
2345        * the actor's children, since it refers only to the current
2346        * actor's allocation.
2347        */
2348       children_flags = flags;
2349       children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
2350
2351       CLUTTER_NOTE (LAYOUT,
2352                     "Allocating %d children of %s "
2353                     "at { %.2f, %.2f - %.2f x %.2f } "
2354                     "using %s",
2355                     priv->n_children,
2356                     _clutter_actor_get_debug_name (self),
2357                     allocation->x1,
2358                     allocation->y1,
2359                     (allocation->x2 - allocation->x1),
2360                     (allocation->y2 - allocation->y1),
2361                     G_OBJECT_TYPE_NAME (priv->layout_manager));
2362
2363       clutter_layout_manager_allocate (priv->layout_manager,
2364                                        container,
2365                                        &children_box,
2366                                        children_flags);
2367     }
2368 }
2369
2370 static void
2371 clutter_actor_real_allocate (ClutterActor           *self,
2372                              const ClutterActorBox  *box,
2373                              ClutterAllocationFlags  flags)
2374 {
2375   ClutterActorPrivate *priv = self->priv;
2376   gboolean changed;
2377
2378   g_object_freeze_notify (G_OBJECT (self));
2379
2380   changed = clutter_actor_set_allocation_internal (self, box, flags);
2381
2382   /* we allocate our children before we notify changes in our geometry,
2383    * so that people connecting to properties will be able to get valid
2384    * data out of the sub-tree of the scene graph that has this actor at
2385    * the root.
2386    */
2387   clutter_actor_maybe_layout_children (self, box, flags);
2388
2389   if (changed)
2390     {
2391       ClutterActorBox signal_box = priv->allocation;
2392       ClutterAllocationFlags signal_flags = priv->allocation_flags;
2393
2394       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
2395                      &signal_box,
2396                      signal_flags);
2397     }
2398
2399   g_object_thaw_notify (G_OBJECT (self));
2400 }
2401
2402 static void
2403 _clutter_actor_signal_queue_redraw (ClutterActor *self,
2404                                     ClutterActor *origin)
2405 {
2406   /* no point in queuing a redraw on a destroyed actor */
2407   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2408     return;
2409
2410   /* NB: We can't bail out early here if the actor is hidden in case
2411    * the actor bas been cloned. In this case the clone will need to
2412    * receive the signal so it can queue its own redraw.
2413    */
2414
2415   /* calls klass->queue_redraw in default handler */
2416   g_signal_emit (self, actor_signals[QUEUE_REDRAW], 0, origin);
2417 }
2418
2419 static void
2420 clutter_actor_real_queue_redraw (ClutterActor *self,
2421                                  ClutterActor *origin)
2422 {
2423   ClutterActor *parent;
2424
2425   CLUTTER_NOTE (PAINT, "Redraw queued on '%s' (from: '%s')",
2426                 _clutter_actor_get_debug_name (self),
2427                 origin != NULL ? _clutter_actor_get_debug_name (origin)
2428                                : "same actor");
2429
2430   /* no point in queuing a redraw on a destroyed actor */
2431   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2432     return;
2433
2434   /* If the queue redraw is coming from a child then the actor has
2435      become dirty and any queued effect is no longer valid */
2436   if (self != origin)
2437     {
2438       self->priv->is_dirty = TRUE;
2439       self->priv->effect_to_redraw = NULL;
2440     }
2441
2442   /* If the actor isn't visible, we still had to emit the signal
2443    * to allow for a ClutterClone, but the appearance of the parent
2444    * won't change so we don't have to propagate up the hierarchy.
2445    */
2446   if (!CLUTTER_ACTOR_IS_VISIBLE (self))
2447     return;
2448
2449   /* Although we could determine here that a full stage redraw
2450    * has already been queued and immediately bail out, we actually
2451    * guarantee that we will propagate a queue-redraw signal to our
2452    * parent at least once so that it's possible to implement a
2453    * container that tracks which of its children have queued a
2454    * redraw.
2455    */
2456   if (self->priv->propagated_one_redraw)
2457     {
2458       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2459       if (stage != NULL &&
2460           _clutter_stage_has_full_redraw_queued (CLUTTER_STAGE (stage)))
2461         return;
2462     }
2463
2464   self->priv->propagated_one_redraw = TRUE;
2465
2466   /* notify parents, if they are all visible eventually we'll
2467    * queue redraw on the stage, which queues the redraw idle.
2468    */
2469   parent = clutter_actor_get_parent (self);
2470   if (parent != NULL)
2471     {
2472       /* this will go up recursively */
2473       _clutter_actor_signal_queue_redraw (parent, origin);
2474     }
2475 }
2476
2477 static void
2478 clutter_actor_real_queue_relayout (ClutterActor *self)
2479 {
2480   ClutterActorPrivate *priv = self->priv;
2481
2482   /* no point in queueing a redraw on a destroyed actor */
2483   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
2484     return;
2485
2486   priv->needs_width_request  = TRUE;
2487   priv->needs_height_request = TRUE;
2488   priv->needs_allocation     = TRUE;
2489
2490   /* reset the cached size requests */
2491   memset (priv->width_requests, 0,
2492           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2493   memset (priv->height_requests, 0,
2494           N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
2495
2496   /* We need to go all the way up the hierarchy */
2497   if (priv->parent != NULL)
2498     _clutter_actor_queue_only_relayout (priv->parent);
2499 }
2500
2501 /**
2502  * clutter_actor_apply_relative_transform_to_point:
2503  * @self: A #ClutterActor
2504  * @ancestor: (allow-none): A #ClutterActor ancestor, or %NULL to use the
2505  *   default #ClutterStage
2506  * @point: A point as #ClutterVertex
2507  * @vertex: (out caller-allocates): The translated #ClutterVertex
2508  *
2509  * Transforms @point in coordinates relative to the actor into
2510  * ancestor-relative coordinates using the relevant transform
2511  * stack (i.e. scale, rotation, etc).
2512  *
2513  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2514  * this case, the coordinates returned will be the coordinates on
2515  * the stage before the projection is applied. This is different from
2516  * the behaviour of clutter_actor_apply_transform_to_point().
2517  *
2518  * Since: 0.6
2519  */
2520 void
2521 clutter_actor_apply_relative_transform_to_point (ClutterActor        *self,
2522                                                  ClutterActor        *ancestor,
2523                                                  const ClutterVertex *point,
2524                                                  ClutterVertex       *vertex)
2525 {
2526   gfloat w;
2527   CoglMatrix matrix;
2528
2529   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2530   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2531   g_return_if_fail (point != NULL);
2532   g_return_if_fail (vertex != NULL);
2533
2534   *vertex = *point;
2535   w = 1.0;
2536
2537   if (ancestor == NULL)
2538     ancestor = _clutter_actor_get_stage_internal (self);
2539
2540   if (ancestor == NULL)
2541     {
2542       *vertex = *point;
2543       return;
2544     }
2545
2546   _clutter_actor_get_relative_transformation_matrix (self, ancestor, &matrix);
2547   cogl_matrix_transform_point (&matrix, &vertex->x, &vertex->y, &vertex->z, &w);
2548 }
2549
2550 static gboolean
2551 _clutter_actor_fully_transform_vertices (ClutterActor *self,
2552                                          const ClutterVertex *vertices_in,
2553                                          ClutterVertex *vertices_out,
2554                                          int n_vertices)
2555 {
2556   ClutterActor *stage;
2557   CoglMatrix modelview;
2558   CoglMatrix projection;
2559   float viewport[4];
2560
2561   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
2562
2563   stage = _clutter_actor_get_stage_internal (self);
2564
2565   /* We really can't do anything meaningful in this case so don't try
2566    * to do any transform */
2567   if (stage == NULL)
2568     return FALSE;
2569
2570   /* Note: we pass NULL as the ancestor because we don't just want the modelview
2571    * that gets us to stage coordinates, we want to go all the way to eye
2572    * coordinates */
2573   _clutter_actor_apply_relative_transformation_matrix (self, NULL, &modelview);
2574
2575   /* Fetch the projection and viewport */
2576   _clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
2577   _clutter_stage_get_viewport (CLUTTER_STAGE (stage),
2578                                &viewport[0],
2579                                &viewport[1],
2580                                &viewport[2],
2581                                &viewport[3]);
2582
2583   _clutter_util_fully_transform_vertices (&modelview,
2584                                           &projection,
2585                                           viewport,
2586                                           vertices_in,
2587                                           vertices_out,
2588                                           n_vertices);
2589
2590   return TRUE;
2591 }
2592
2593 /**
2594  * clutter_actor_apply_transform_to_point:
2595  * @self: A #ClutterActor
2596  * @point: A point as #ClutterVertex
2597  * @vertex: (out caller-allocates): The translated #ClutterVertex
2598  *
2599  * Transforms @point in coordinates relative to the actor
2600  * into screen-relative coordinates with the current actor
2601  * transformation (i.e. scale, rotation, etc)
2602  *
2603  * Since: 0.4
2604  **/
2605 void
2606 clutter_actor_apply_transform_to_point (ClutterActor        *self,
2607                                         const ClutterVertex *point,
2608                                         ClutterVertex       *vertex)
2609 {
2610   g_return_if_fail (point != NULL);
2611   g_return_if_fail (vertex != NULL);
2612   _clutter_actor_fully_transform_vertices (self, point, vertex, 1);
2613 }
2614
2615 /*
2616  * _clutter_actor_get_relative_transformation_matrix:
2617  * @self: The actor whose coordinate space you want to transform from.
2618  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2619  *            or %NULL if you want to transform all the way to eye coordinates.
2620  * @matrix: A #CoglMatrix to store the transformation
2621  *
2622  * This gets a transformation @matrix that will transform coordinates from the
2623  * coordinate space of @self into the coordinate space of @ancestor.
2624  *
2625  * For example if you need a matrix that can transform the local actor
2626  * coordinates of @self into stage coordinates you would pass the actor's stage
2627  * pointer as the @ancestor.
2628  *
2629  * If you pass %NULL then the transformation will take you all the way through
2630  * to eye coordinates. This can be useful if you want to extract the entire
2631  * modelview transform that Clutter applies before applying the projection
2632  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2633  * using cogl_set_modelview_matrix() for example then you would want a matrix
2634  * that transforms into eye coordinates.
2635  *
2636  * <note><para>This function explicitly initializes the given @matrix. If you just
2637  * want clutter to multiply a relative transformation with an existing matrix
2638  * you can use clutter_actor_apply_relative_transformation_matrix()
2639  * instead.</para></note>
2640  *
2641  */
2642 /* XXX: We should consider caching the stage relative modelview along with
2643  * the actor itself */
2644 static void
2645 _clutter_actor_get_relative_transformation_matrix (ClutterActor *self,
2646                                                    ClutterActor *ancestor,
2647                                                    CoglMatrix *matrix)
2648 {
2649   cogl_matrix_init_identity (matrix);
2650
2651   _clutter_actor_apply_relative_transformation_matrix (self, ancestor, matrix);
2652 }
2653
2654 /* Project the given @box into stage window coordinates, writing the
2655  * transformed vertices to @verts[]. */
2656 static gboolean
2657 _clutter_actor_transform_and_project_box (ClutterActor          *self,
2658                                           const ClutterActorBox *box,
2659                                           ClutterVertex          verts[])
2660 {
2661   ClutterVertex box_vertices[4];
2662
2663   box_vertices[0].x = box->x1;
2664   box_vertices[0].y = box->y1;
2665   box_vertices[0].z = 0;
2666   box_vertices[1].x = box->x2;
2667   box_vertices[1].y = box->y1;
2668   box_vertices[1].z = 0;
2669   box_vertices[2].x = box->x1;
2670   box_vertices[2].y = box->y2;
2671   box_vertices[2].z = 0;
2672   box_vertices[3].x = box->x2;
2673   box_vertices[3].y = box->y2;
2674   box_vertices[3].z = 0;
2675
2676   return
2677     _clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
2678 }
2679
2680 /**
2681  * clutter_actor_get_allocation_vertices:
2682  * @self: A #ClutterActor
2683  * @ancestor: (allow-none): A #ClutterActor to calculate the vertices
2684  *   against, or %NULL to use the #ClutterStage
2685  * @verts: (out) (array fixed-size=4) (element-type Clutter.Vertex): return
2686  *   location for an array of 4 #ClutterVertex in which to store the result
2687  *
2688  * Calculates the transformed coordinates of the four corners of the
2689  * actor in the plane of @ancestor. The returned vertices relate to
2690  * the #ClutterActorBox coordinates as follows:
2691  * <itemizedlist>
2692  *   <listitem><para>@verts[0] contains (x1, y1)</para></listitem>
2693  *   <listitem><para>@verts[1] contains (x2, y1)</para></listitem>
2694  *   <listitem><para>@verts[2] contains (x1, y2)</para></listitem>
2695  *   <listitem><para>@verts[3] contains (x2, y2)</para></listitem>
2696  * </itemizedlist>
2697  *
2698  * If @ancestor is %NULL the ancestor will be the #ClutterStage. In
2699  * this case, the coordinates returned will be the coordinates on
2700  * the stage before the projection is applied. This is different from
2701  * the behaviour of clutter_actor_get_abs_allocation_vertices().
2702  *
2703  * Since: 0.6
2704  */
2705 void
2706 clutter_actor_get_allocation_vertices (ClutterActor  *self,
2707                                        ClutterActor  *ancestor,
2708                                        ClutterVertex  verts[])
2709 {
2710   ClutterActorPrivate *priv;
2711   ClutterActorBox box;
2712   ClutterVertex vertices[4];
2713   CoglMatrix modelview;
2714
2715   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2716   g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
2717
2718   if (ancestor == NULL)
2719     ancestor = _clutter_actor_get_stage_internal (self);
2720
2721   /* Fallback to a NOP transform if the actor isn't parented under a
2722    * stage. */
2723   if (ancestor == NULL)
2724     ancestor = self;
2725
2726   priv = self->priv;
2727
2728   /* if the actor needs to be allocated we force a relayout, so that
2729    * we will have valid values to use in the transformations */
2730   if (priv->needs_allocation)
2731     {
2732       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2733       if (stage)
2734         _clutter_stage_maybe_relayout (stage);
2735       else
2736         {
2737           box.x1 = box.y1 = 0;
2738           /* The result isn't really meaningful in this case but at
2739            * least try to do something *vaguely* reasonable... */
2740           clutter_actor_get_size (self, &box.x2, &box.y2);
2741         }
2742     }
2743
2744   clutter_actor_get_allocation_box (self, &box);
2745
2746   vertices[0].x = box.x1;
2747   vertices[0].y = box.y1;
2748   vertices[0].z = 0;
2749   vertices[1].x = box.x2;
2750   vertices[1].y = box.y1;
2751   vertices[1].z = 0;
2752   vertices[2].x = box.x1;
2753   vertices[2].y = box.y2;
2754   vertices[2].z = 0;
2755   vertices[3].x = box.x2;
2756   vertices[3].y = box.y2;
2757   vertices[3].z = 0;
2758
2759   _clutter_actor_get_relative_transformation_matrix (self, ancestor,
2760                                                      &modelview);
2761
2762   cogl_matrix_transform_points (&modelview,
2763                                 3,
2764                                 sizeof (ClutterVertex),
2765                                 vertices,
2766                                 sizeof (ClutterVertex),
2767                                 vertices,
2768                                 4);
2769 }
2770
2771 /**
2772  * clutter_actor_get_abs_allocation_vertices:
2773  * @self: A #ClutterActor
2774  * @verts: (out) (array fixed-size=4): Pointer to a location of an array
2775  *   of 4 #ClutterVertex where to store the result.
2776  *
2777  * Calculates the transformed screen coordinates of the four corners of
2778  * the actor; the returned vertices relate to the #ClutterActorBox
2779  * coordinates  as follows:
2780  * <itemizedlist>
2781  *   <listitem><para>v[0] contains (x1, y1)</para></listitem>
2782  *   <listitem><para>v[1] contains (x2, y1)</para></listitem>
2783  *   <listitem><para>v[2] contains (x1, y2)</para></listitem>
2784  *   <listitem><para>v[3] contains (x2, y2)</para></listitem>
2785  * </itemizedlist>
2786  *
2787  * Since: 0.4
2788  */
2789 void
2790 clutter_actor_get_abs_allocation_vertices (ClutterActor  *self,
2791                                            ClutterVertex  verts[])
2792 {
2793   ClutterActorPrivate *priv;
2794   ClutterActorBox actor_space_allocation;
2795
2796   g_return_if_fail (CLUTTER_IS_ACTOR (self));
2797
2798   priv = self->priv;
2799
2800   /* if the actor needs to be allocated we force a relayout, so that
2801    * the actor allocation box will be valid for
2802    * _clutter_actor_transform_and_project_box()
2803    */
2804   if (priv->needs_allocation)
2805     {
2806       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
2807       /* There's nothing meaningful we can do now */
2808       if (!stage)
2809         return;
2810
2811       _clutter_stage_maybe_relayout (stage);
2812     }
2813
2814   /* NB: _clutter_actor_transform_and_project_box expects a box in the actor's
2815    * own coordinate space... */
2816   actor_space_allocation.x1 = 0;
2817   actor_space_allocation.y1 = 0;
2818   actor_space_allocation.x2 = priv->allocation.x2 - priv->allocation.x1;
2819   actor_space_allocation.y2 = priv->allocation.y2 - priv->allocation.y1;
2820   _clutter_actor_transform_and_project_box (self,
2821                                             &actor_space_allocation,
2822                                             verts);
2823 }
2824
2825 static void
2826 clutter_actor_real_apply_transform (ClutterActor *self,
2827                                     CoglMatrix   *matrix)
2828 {
2829   ClutterActorPrivate *priv = self->priv;
2830
2831   if (!priv->transform_valid)
2832     {
2833       CoglMatrix *transform = &priv->transform;
2834       const ClutterTransformInfo *info;
2835
2836       info = _clutter_actor_get_transform_info_or_defaults (self);
2837
2838       cogl_matrix_init_identity (transform);
2839
2840       cogl_matrix_translate (transform,
2841                              priv->allocation.x1,
2842                              priv->allocation.y1,
2843                              0.0);
2844
2845       if (info->depth)
2846         cogl_matrix_translate (transform, 0, 0, info->depth);
2847
2848       /*
2849        * because the rotation involves translations, we must scale
2850        * before applying the rotations (if we apply the scale after
2851        * the rotations, the translations included in the rotation are
2852        * not scaled and so the entire object will move on the screen
2853        * as a result of rotating it).
2854        */
2855       if (info->scale_x != 1.0 || info->scale_y != 1.0)
2856         {
2857           TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2858                                         &info->scale_center,
2859                                         cogl_matrix_scale (transform,
2860                                                            info->scale_x,
2861                                                            info->scale_y,
2862                                                            1.0));
2863         }
2864
2865       if (info->rz_angle)
2866         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2867                                       &info->rz_center,
2868                                       cogl_matrix_rotate (transform,
2869                                                           info->rz_angle,
2870                                                           0, 0, 1.0));
2871
2872       if (info->ry_angle)
2873         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2874                                       &info->ry_center,
2875                                       cogl_matrix_rotate (transform,
2876                                                           info->ry_angle,
2877                                                           0, 1.0, 0));
2878
2879       if (info->rx_angle)
2880         TRANSFORM_ABOUT_ANCHOR_COORD (self, transform,
2881                                       &info->rx_center,
2882                                       cogl_matrix_rotate (transform,
2883                                                           info->rx_angle,
2884                                                           1.0, 0, 0));
2885
2886       if (!clutter_anchor_coord_is_zero (&info->anchor))
2887         {
2888           gfloat x, y, z;
2889
2890           clutter_anchor_coord_get_units (self, &info->anchor, &x, &y, &z);
2891           cogl_matrix_translate (transform, -x, -y, -z);
2892         }
2893
2894       priv->transform_valid = TRUE;
2895     }
2896
2897   cogl_matrix_multiply (matrix, matrix, &priv->transform);
2898 }
2899
2900 /* Applies the transforms associated with this actor to the given
2901  * matrix. */
2902 void
2903 _clutter_actor_apply_modelview_transform (ClutterActor *self,
2904                                           CoglMatrix *matrix)
2905 {
2906   CLUTTER_ACTOR_GET_CLASS (self)->apply_transform (self, matrix);
2907 }
2908
2909 /*
2910  * clutter_actor_apply_relative_transformation_matrix:
2911  * @self: The actor whose coordinate space you want to transform from.
2912  * @ancestor: The ancestor actor whose coordinate space you want to transform too
2913  *            or %NULL if you want to transform all the way to eye coordinates.
2914  * @matrix: A #CoglMatrix to apply the transformation too.
2915  *
2916  * This multiplies a transform with @matrix that will transform coordinates
2917  * from the coordinate space of @self into the coordinate space of @ancestor.
2918  *
2919  * For example if you need a matrix that can transform the local actor
2920  * coordinates of @self into stage coordinates you would pass the actor's stage
2921  * pointer as the @ancestor.
2922  *
2923  * If you pass %NULL then the transformation will take you all the way through
2924  * to eye coordinates. This can be useful if you want to extract the entire
2925  * modelview transform that Clutter applies before applying the projection
2926  * transformation. If you want to explicitly set a modelview on a CoglFramebuffer
2927  * using cogl_set_modelview_matrix() for example then you would want a matrix
2928  * that transforms into eye coordinates.
2929  *
2930  * <note>This function doesn't initialize the given @matrix, it simply
2931  * multiplies the requested transformation matrix with the existing contents of
2932  * @matrix. You can use cogl_matrix_init_identity() to initialize the @matrix
2933  * before calling this function, or you can use
2934  * clutter_actor_get_relative_transformation_matrix() instead.</note>
2935  */
2936 void
2937 _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
2938                                                      ClutterActor *ancestor,
2939                                                      CoglMatrix *matrix)
2940 {
2941   ClutterActor *parent;
2942
2943   /* Note we terminate before ever calling stage->apply_transform()
2944    * since that would conceptually be relative to the underlying
2945    * window OpenGL coordinates so we'd need a special @ancestor
2946    * value to represent the fake parent of the stage. */
2947   if (self == ancestor)
2948     return;
2949
2950   parent = clutter_actor_get_parent (self);
2951
2952   if (parent != NULL)
2953     _clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
2954                                                          matrix);
2955
2956   _clutter_actor_apply_modelview_transform (self, matrix);
2957 }
2958
2959 static void
2960 _clutter_actor_draw_paint_volume_full (ClutterActor *self,
2961                                        ClutterPaintVolume *pv,
2962                                        const char *label,
2963                                        const CoglColor *color)
2964 {
2965   static CoglPipeline *outline = NULL;
2966   CoglPrimitive *prim;
2967   ClutterVertex line_ends[12 * 2];
2968   int n_vertices;
2969   CoglContext *ctx =
2970     clutter_backend_get_cogl_context (clutter_get_default_backend ());
2971   /* XXX: at some point we'll query this from the stage but we can't
2972    * do that until the osx backend uses Cogl natively. */
2973   CoglFramebuffer *fb = cogl_get_draw_framebuffer ();
2974
2975   if (outline == NULL)
2976     outline = cogl_pipeline_new (ctx);
2977
2978   _clutter_paint_volume_complete (pv);
2979
2980   n_vertices = pv->is_2d ? 4 * 2 : 12 * 2;
2981
2982   /* Front face */
2983   line_ends[0] = pv->vertices[0]; line_ends[1] = pv->vertices[1];
2984   line_ends[2] = pv->vertices[1]; line_ends[3] = pv->vertices[2];
2985   line_ends[4] = pv->vertices[2]; line_ends[5] = pv->vertices[3];
2986   line_ends[6] = pv->vertices[3]; line_ends[7] = pv->vertices[0];
2987
2988   if (!pv->is_2d)
2989     {
2990       /* Back face */
2991       line_ends[8] = pv->vertices[4]; line_ends[9] = pv->vertices[5];
2992       line_ends[10] = pv->vertices[5]; line_ends[11] = pv->vertices[6];
2993       line_ends[12] = pv->vertices[6]; line_ends[13] = pv->vertices[7];
2994       line_ends[14] = pv->vertices[7]; line_ends[15] = pv->vertices[4];
2995
2996       /* Lines connecting front face to back face */
2997       line_ends[16] = pv->vertices[0]; line_ends[17] = pv->vertices[4];
2998       line_ends[18] = pv->vertices[1]; line_ends[19] = pv->vertices[5];
2999       line_ends[20] = pv->vertices[2]; line_ends[21] = pv->vertices[6];
3000       line_ends[22] = pv->vertices[3]; line_ends[23] = pv->vertices[7];
3001     }
3002
3003   prim = cogl_primitive_new_p3 (ctx, COGL_VERTICES_MODE_LINES,
3004                                 n_vertices,
3005                                 (CoglVertexP3 *)line_ends);
3006
3007   cogl_pipeline_set_color (outline, color);
3008   cogl_framebuffer_draw_primitive (fb, outline, prim);
3009   cogl_object_unref (prim);
3010
3011   if (label)
3012     {
3013       PangoLayout *layout;
3014       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3015       pango_layout_set_text (layout, label, -1);
3016       cogl_pango_render_layout (layout,
3017                                 pv->vertices[0].x,
3018                                 pv->vertices[0].y,
3019                                 color,
3020                                 0);
3021       g_object_unref (layout);
3022     }
3023 }
3024
3025 static void
3026 _clutter_actor_draw_paint_volume (ClutterActor *self)
3027 {
3028   ClutterPaintVolume *pv;
3029   CoglColor color;
3030
3031   pv = _clutter_actor_get_paint_volume_mutable (self);
3032   if (!pv)
3033     {
3034       gfloat width, height;
3035       ClutterPaintVolume fake_pv;
3036
3037       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
3038       _clutter_paint_volume_init_static (&fake_pv, stage);
3039
3040       clutter_actor_get_size (self, &width, &height);
3041       clutter_paint_volume_set_width (&fake_pv, width);
3042       clutter_paint_volume_set_height (&fake_pv, height);
3043
3044       cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3045       _clutter_actor_draw_paint_volume_full (self, &fake_pv,
3046                                              _clutter_actor_get_debug_name (self),
3047                                              &color);
3048
3049       clutter_paint_volume_free (&fake_pv);
3050     }
3051   else
3052     {
3053       cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3054       _clutter_actor_draw_paint_volume_full (self, pv,
3055                                              _clutter_actor_get_debug_name (self),
3056                                              &color);
3057     }
3058 }
3059
3060 static void
3061 _clutter_actor_paint_cull_result (ClutterActor *self,
3062                                   gboolean success,
3063                                   ClutterCullResult result)
3064 {
3065   ClutterPaintVolume *pv;
3066   CoglColor color;
3067
3068   if (success)
3069     {
3070       if (result == CLUTTER_CULL_RESULT_IN)
3071         cogl_color_init_from_4f (&color, 0, 1, 0, 1);
3072       else if (result == CLUTTER_CULL_RESULT_OUT)
3073         cogl_color_init_from_4f (&color, 0, 0, 1, 1);
3074       else
3075         cogl_color_init_from_4f (&color, 0, 1, 1, 1);
3076     }
3077   else
3078     cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3079
3080   if (success && (pv = _clutter_actor_get_paint_volume_mutable (self)))
3081     _clutter_actor_draw_paint_volume_full (self, pv,
3082                                            _clutter_actor_get_debug_name (self),
3083                                            &color);
3084   else
3085     {
3086       PangoLayout *layout;
3087       char *label =
3088         g_strdup_printf ("CULL FAILURE: %s", _clutter_actor_get_debug_name (self));
3089       cogl_color_init_from_4f (&color, 1, 1, 1, 1);
3090       cogl_set_source_color (&color);
3091
3092       layout = pango_layout_new (clutter_actor_get_pango_context (self));
3093       pango_layout_set_text (layout, label, -1);
3094       cogl_pango_render_layout (layout,
3095                                 0,
3096                                 0,
3097                                 &color,
3098                                 0);
3099       g_free (label);
3100       g_object_unref (layout);
3101     }
3102 }
3103
3104 static int clone_paint_level = 0;
3105
3106 void
3107 _clutter_actor_push_clone_paint (void)
3108 {
3109   clone_paint_level++;
3110 }
3111
3112 void
3113 _clutter_actor_pop_clone_paint (void)
3114 {
3115   clone_paint_level--;
3116 }
3117
3118 static gboolean
3119 in_clone_paint (void)
3120 {
3121   return clone_paint_level > 0;
3122 }
3123
3124 /* Returns TRUE if the actor can be ignored */
3125 /* FIXME: we should return a ClutterCullResult, and
3126  * clutter_actor_paint should understand that a CLUTTER_CULL_RESULT_IN
3127  * means there's no point in trying to cull descendants of the current
3128  * node. */
3129 static gboolean
3130 cull_actor (ClutterActor *self, ClutterCullResult *result_out)
3131 {
3132   ClutterActorPrivate *priv = self->priv;
3133   ClutterActor *stage;
3134   const ClutterPlane *stage_clip;
3135
3136   if (!priv->last_paint_volume_valid)
3137     {
3138       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3139                     "->last_paint_volume_valid == FALSE",
3140                     _clutter_actor_get_debug_name (self));
3141       return FALSE;
3142     }
3143
3144   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CULLING))
3145     return FALSE;
3146
3147   stage = _clutter_actor_get_stage_internal (self);
3148   stage_clip = _clutter_stage_get_clip (CLUTTER_STAGE (stage));
3149   if (G_UNLIKELY (!stage_clip))
3150     {
3151       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3152                     "No stage clip set",
3153                     _clutter_actor_get_debug_name (self));
3154       return FALSE;
3155     }
3156
3157   if (cogl_get_draw_framebuffer () !=
3158       _clutter_stage_get_active_framebuffer (CLUTTER_STAGE (stage)))
3159     {
3160       CLUTTER_NOTE (CLIPPING, "Bail from cull_actor without culling (%s): "
3161                     "Current framebuffer doesn't correspond to stage",
3162                     _clutter_actor_get_debug_name (self));
3163       return FALSE;
3164     }
3165
3166   *result_out =
3167     _clutter_paint_volume_cull (&priv->last_paint_volume, stage_clip);
3168   return TRUE;
3169 }
3170
3171 static void
3172 _clutter_actor_update_last_paint_volume (ClutterActor *self)
3173 {
3174   ClutterActorPrivate *priv = self->priv;
3175   const ClutterPaintVolume *pv;
3176
3177   if (priv->last_paint_volume_valid)
3178     {
3179       clutter_paint_volume_free (&priv->last_paint_volume);
3180       priv->last_paint_volume_valid = FALSE;
3181     }
3182
3183   pv = clutter_actor_get_paint_volume (self);
3184   if (!pv)
3185     {
3186       CLUTTER_NOTE (CLIPPING, "Bail from update_last_paint_volume (%s): "
3187                     "Actor failed to report a paint volume",
3188                     _clutter_actor_get_debug_name (self));
3189       return;
3190     }
3191
3192   _clutter_paint_volume_copy_static (pv, &priv->last_paint_volume);
3193
3194   _clutter_paint_volume_transform_relative (&priv->last_paint_volume,
3195                                             NULL); /* eye coordinates */
3196
3197   priv->last_paint_volume_valid = TRUE;
3198 }
3199
3200 static inline gboolean
3201 actor_has_shader_data (ClutterActor *self)
3202 {
3203   return g_object_get_qdata (G_OBJECT (self), quark_shader_data) != NULL;
3204 }
3205
3206 guint32
3207 _clutter_actor_get_pick_id (ClutterActor *self)
3208 {
3209   if (self->priv->pick_id < 0)
3210     return 0;
3211
3212   return self->priv->pick_id;
3213 }
3214
3215 /* This is the same as clutter_actor_add_effect except that it doesn't
3216    queue a redraw and it doesn't notify on the effect property */
3217 static void
3218 _clutter_actor_add_effect_internal (ClutterActor  *self,
3219                                     ClutterEffect *effect)
3220 {
3221   ClutterActorPrivate *priv = self->priv;
3222
3223   if (priv->effects == NULL)
3224     {
3225       priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
3226       priv->effects->actor = self;
3227     }
3228
3229   _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3230 }
3231
3232 /* This is the same as clutter_actor_remove_effect except that it doesn't
3233    queue a redraw and it doesn't notify on the effect property */
3234 static void
3235 _clutter_actor_remove_effect_internal (ClutterActor  *self,
3236                                        ClutterEffect *effect)
3237 {
3238   ClutterActorPrivate *priv = self->priv;
3239
3240   if (priv->effects == NULL)
3241     return;
3242
3243   _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
3244
3245   if (_clutter_meta_group_peek_metas (priv->effects) == NULL)
3246     g_clear_object (&priv->effects);
3247 }
3248
3249 static gboolean
3250 needs_flatten_effect (ClutterActor *self)
3251 {
3252   ClutterActorPrivate *priv = self->priv;
3253
3254   if (G_UNLIKELY (clutter_paint_debug_flags &
3255                   CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
3256     return FALSE;
3257
3258   if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
3259     return TRUE;
3260   else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
3261     {
3262       if (clutter_actor_get_paint_opacity (self) < 255 &&
3263           clutter_actor_has_overlaps (self))
3264         return TRUE;
3265     }
3266
3267   return FALSE;
3268 }
3269
3270 static void
3271 add_or_remove_flatten_effect (ClutterActor *self)
3272 {
3273   ClutterActorPrivate *priv = self->priv;
3274
3275   /* Add or remove the flatten effect depending on the
3276      offscreen-redirect property. */
3277   if (needs_flatten_effect (self))
3278     {
3279       if (priv->flatten_effect == NULL)
3280         {
3281           ClutterActorMeta *actor_meta;
3282           gint priority;
3283
3284           priv->flatten_effect = _clutter_flatten_effect_new ();
3285           /* Keep a reference to the effect so that we can queue
3286              redraws from it */
3287           g_object_ref_sink (priv->flatten_effect);
3288
3289           /* Set the priority of the effect to high so that it will
3290              always be applied to the actor first. It uses an internal
3291              priority so that it won't be visible to applications */
3292           actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
3293           priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
3294           _clutter_actor_meta_set_priority (actor_meta, priority);
3295
3296           /* This will add the effect without queueing a redraw */
3297           _clutter_actor_add_effect_internal (self, priv->flatten_effect);
3298         }
3299     }
3300   else
3301     {
3302       if (priv->flatten_effect != NULL)
3303         {
3304           /* Destroy the effect so that it will lose its fbo cache of
3305              the actor */
3306           _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
3307           g_clear_object (&priv->flatten_effect);
3308         }
3309     }
3310 }
3311
3312 static void
3313 clutter_actor_real_paint (ClutterActor *actor)
3314 {
3315   ClutterActorPrivate *priv = actor->priv;
3316   ClutterActor *iter;
3317
3318   for (iter = priv->first_child;
3319        iter != NULL;
3320        iter = iter->priv->next_sibling)
3321     {
3322       CLUTTER_NOTE (PAINT, "Painting %s, child of %s, at { %.2f, %.2f - %.2f x %.2f }",
3323                     _clutter_actor_get_debug_name (iter),
3324                     _clutter_actor_get_debug_name (actor),
3325                     iter->priv->allocation.x1,
3326                     iter->priv->allocation.y1,
3327                     iter->priv->allocation.x2 - iter->priv->allocation.x1,
3328                     iter->priv->allocation.y2 - iter->priv->allocation.y1);
3329
3330       clutter_actor_paint (iter);
3331     }
3332 }
3333
3334 static gboolean
3335 clutter_actor_paint_node (ClutterActor     *actor,
3336                           ClutterPaintNode *root)
3337 {
3338   ClutterActorPrivate *priv = actor->priv;
3339
3340   if (root == NULL)
3341     return FALSE;
3342
3343   if (priv->bg_color_set &&
3344       !clutter_color_equal (&priv->bg_color, CLUTTER_COLOR_Transparent))
3345     {
3346       ClutterPaintNode *node;
3347       ClutterColor bg_color;
3348       ClutterActorBox box;
3349
3350       box.x1 = 0.f;
3351       box.y1 = 0.f;
3352       box.x2 = clutter_actor_box_get_width (&priv->allocation);
3353       box.y2 = clutter_actor_box_get_height (&priv->allocation);
3354
3355       bg_color = priv->bg_color;
3356       bg_color.alpha = clutter_actor_get_paint_opacity_internal (actor)
3357                      * priv->bg_color.alpha
3358                      / 255;
3359
3360       node = clutter_color_node_new (&bg_color);
3361       clutter_paint_node_set_name (node, "backgroundColor");
3362       clutter_paint_node_add_rectangle (node, &box);
3363       clutter_paint_node_add_child (root, node);
3364       clutter_paint_node_unref (node);
3365     }
3366
3367   if (priv->content != NULL)
3368     _clutter_content_paint_content (priv->content, actor, root);
3369
3370   if (CLUTTER_ACTOR_GET_CLASS (actor)->paint_node != NULL)
3371     CLUTTER_ACTOR_GET_CLASS (actor)->paint_node (actor, root);
3372
3373   if (clutter_paint_node_get_n_children (root) == 0)
3374     return FALSE;
3375
3376 #ifdef CLUTTER_ENABLE_DEBUG
3377   if (CLUTTER_HAS_DEBUG (PAINT))
3378     {
3379       /* dump the tree only if we have one */
3380       _clutter_paint_node_dump_tree (root);
3381     }
3382 #endif /* CLUTTER_ENABLE_DEBUG */
3383
3384   _clutter_paint_node_paint (root);
3385
3386 #if 0
3387   /* XXX: Uncomment this when we disable emitting the paint signal */
3388   CLUTTER_ACTOR_GET_CLASS (actor)->paint (actor);
3389 #endif
3390
3391   return TRUE;
3392 }
3393
3394 /**
3395  * clutter_actor_paint:
3396  * @self: A #ClutterActor
3397  *
3398  * Renders the actor to display.
3399  *
3400  * This function should not be called directly by applications.
3401  * Call clutter_actor_queue_redraw() to queue paints, instead.
3402  *
3403  * This function is context-aware, and will either cause a
3404  * regular paint or a pick paint.
3405  *
3406  * This function will emit the #ClutterActor::paint signal or
3407  * the #ClutterActor::pick signal, depending on the context.
3408  *
3409  * This function does not paint the actor if the actor is set to 0,
3410  * unless it is performing a pick paint.
3411  */
3412 void
3413 clutter_actor_paint (ClutterActor *self)
3414 {
3415   ClutterActorPrivate *priv;
3416   ClutterPickMode pick_mode;
3417   gboolean clip_set = FALSE;
3418   gboolean shader_applied = FALSE;
3419
3420   CLUTTER_STATIC_COUNTER (actor_paint_counter,
3421                           "Actor real-paint counter",
3422                           "Increments each time any actor is painted",
3423                           0 /* no application private data */);
3424   CLUTTER_STATIC_COUNTER (actor_pick_counter,
3425                           "Actor pick-paint counter",
3426                           "Increments each time any actor is painted "
3427                           "for picking",
3428                           0 /* no application private data */);
3429
3430   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3431
3432   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
3433     return;
3434
3435   priv = self->priv;
3436
3437   pick_mode = _clutter_context_get_pick_mode ();
3438
3439   if (pick_mode == CLUTTER_PICK_NONE)
3440     priv->propagated_one_redraw = FALSE;
3441
3442   /* It's an important optimization that we consider painting of
3443    * actors with 0 opacity to be a NOP... */
3444   if (pick_mode == CLUTTER_PICK_NONE &&
3445       /* ignore top-levels, since they might be transparent */
3446       !CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
3447       /* Use the override opacity if its been set */
3448       ((priv->opacity_override >= 0) ?
3449        priv->opacity_override : priv->opacity) == 0)
3450     return;
3451
3452   /* if we aren't paintable (not in a toplevel with all
3453    * parents paintable) then do nothing.
3454    */
3455   if (!CLUTTER_ACTOR_IS_MAPPED (self))
3456     return;
3457
3458   /* mark that we are in the paint process */
3459   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3460
3461   cogl_push_matrix();
3462
3463   if (priv->enable_model_view_transform)
3464     {
3465       CoglMatrix matrix;
3466
3467       /* XXX: It could be better to cache the modelview with the actor
3468        * instead of progressively building up the transformations on
3469        * the matrix stack every time we paint. */
3470       cogl_get_modelview_matrix (&matrix);
3471       _clutter_actor_apply_modelview_transform (self, &matrix);
3472
3473 #ifdef CLUTTER_ENABLE_DEBUG
3474       /* Catch when out-of-band transforms have been made by actors not as part
3475        * of an apply_transform vfunc... */
3476       if (G_UNLIKELY (clutter_debug_flags & CLUTTER_DEBUG_OOB_TRANSFORMS))
3477         {
3478           CoglMatrix expected_matrix;
3479
3480           _clutter_actor_get_relative_transformation_matrix (self, NULL,
3481                                                              &expected_matrix);
3482
3483           if (!cogl_matrix_equal (&matrix, &expected_matrix))
3484             {
3485               GString *buf = g_string_sized_new (1024);
3486               ClutterActor *parent;
3487
3488               parent = self;
3489               while (parent != NULL)
3490                 {
3491                   g_string_append (buf, _clutter_actor_get_debug_name (parent));
3492
3493                   if (parent->priv->parent != NULL)
3494                     g_string_append (buf, "->");
3495
3496                   parent = parent->priv->parent;
3497                 }
3498
3499               g_warning ("Unexpected transform found when painting actor "
3500                          "\"%s\". This will be caused by one of the actor's "
3501                          "ancestors (%s) using the Cogl API directly to transform "
3502                          "children instead of using ::apply_transform().",
3503                          _clutter_actor_get_debug_name (self),
3504                          buf->str);
3505
3506               g_string_free (buf, TRUE);
3507             }
3508         }
3509 #endif /* CLUTTER_ENABLE_DEBUG */
3510
3511       cogl_set_modelview_matrix (&matrix);
3512     }
3513
3514   if (priv->has_clip)
3515     {
3516       cogl_clip_push_rectangle (priv->clip.x,
3517                                 priv->clip.y,
3518                                 priv->clip.x + priv->clip.width,
3519                                 priv->clip.y + priv->clip.height);
3520       clip_set = TRUE;
3521     }
3522   else if (priv->clip_to_allocation)
3523     {
3524       gfloat width, height;
3525
3526       width  = priv->allocation.x2 - priv->allocation.x1;
3527       height = priv->allocation.y2 - priv->allocation.y1;
3528
3529       cogl_clip_push_rectangle (0, 0, width, height);
3530       clip_set = TRUE;
3531     }
3532
3533   if (pick_mode == CLUTTER_PICK_NONE)
3534     {
3535       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
3536
3537       /* We check whether we need to add the flatten effect before
3538          each paint so that we can avoid having a mechanism for
3539          applications to notify when the value of the
3540          has_overlaps virtual changes. */
3541       add_or_remove_flatten_effect (self);
3542     }
3543   else
3544     CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_pick_counter);
3545
3546   /* We save the current paint volume so that the next time the
3547    * actor queues a redraw we can constrain the redraw to just
3548    * cover the union of the new bounding box and the old.
3549    *
3550    * We also fetch the current paint volume to perform culling so
3551    * we can avoid painting actors outside the current clip region.
3552    *
3553    * If we are painting inside a clone, we should neither update
3554    * the paint volume or use it to cull painting, since the paint
3555    * box represents the location of the source actor on the
3556    * screen.
3557    *
3558    * XXX: We are starting to do a lot of vertex transforms on
3559    * the CPU in a typical paint, so at some point we should
3560    * audit these and consider caching some things.
3561    *
3562    * NB: We don't perform culling while picking at this point because
3563    * clutter-stage.c doesn't setup the clipping planes appropriately.
3564    *
3565    * NB: We don't want to update the last-paint-volume during picking
3566    * because the last-paint-volume is used to determine the old screen
3567    * space location of an actor that has moved so we can know the
3568    * minimal region to redraw to clear an old view of the actor. If we
3569    * update this during picking then by the time we come around to
3570    * paint then the last-paint-volume would likely represent the new
3571    * actor position not the old.
3572    */
3573   if (!in_clone_paint () && pick_mode == CLUTTER_PICK_NONE)
3574     {
3575       gboolean success;
3576       /* annoyingly gcc warns if uninitialized even though
3577        * the initialization is redundant :-( */
3578       ClutterCullResult result = CLUTTER_CULL_RESULT_IN;
3579
3580       if (G_LIKELY ((clutter_paint_debug_flags &
3581                      (CLUTTER_DEBUG_DISABLE_CULLING |
3582                       CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)) !=
3583                     (CLUTTER_DEBUG_DISABLE_CULLING |
3584                      CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
3585         _clutter_actor_update_last_paint_volume (self);
3586
3587       success = cull_actor (self, &result);
3588
3589       if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))
3590         _clutter_actor_paint_cull_result (self, success, result);
3591       else if (result == CLUTTER_CULL_RESULT_OUT && success)
3592         goto done;
3593     }
3594
3595   if (priv->effects == NULL)
3596     {
3597       if (pick_mode == CLUTTER_PICK_NONE &&
3598           actor_has_shader_data (self))
3599         {
3600           _clutter_actor_shader_pre_paint (self, FALSE);
3601           shader_applied = TRUE;
3602         }
3603
3604       priv->next_effect_to_paint = NULL;
3605     }
3606   else
3607     priv->next_effect_to_paint =
3608       _clutter_meta_group_peek_metas (priv->effects);
3609
3610   clutter_actor_continue_paint (self);
3611
3612   if (shader_applied)
3613     _clutter_actor_shader_post_paint (self);
3614
3615   if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_VOLUMES &&
3616                   pick_mode == CLUTTER_PICK_NONE))
3617     _clutter_actor_draw_paint_volume (self);
3618
3619 done:
3620   /* If we make it here then the actor has run through a complete
3621      paint run including all the effects so it's no longer dirty */
3622   if (pick_mode == CLUTTER_PICK_NONE)
3623     priv->is_dirty = FALSE;
3624
3625   if (clip_set)
3626     cogl_clip_pop();
3627
3628   cogl_pop_matrix();
3629
3630   /* paint sequence complete */
3631   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_PAINT);
3632 }
3633
3634 /**
3635  * clutter_actor_continue_paint:
3636  * @self: A #ClutterActor
3637  *
3638  * Run the next stage of the paint sequence. This function should only
3639  * be called within the implementation of the ‘run’ virtual of a
3640  * #ClutterEffect. It will cause the run method of the next effect to
3641  * be applied, or it will paint the actual actor if the current effect
3642  * is the last effect in the chain.
3643  *
3644  * Since: 1.8
3645  */
3646 void
3647 clutter_actor_continue_paint (ClutterActor *self)
3648 {
3649   ClutterActorPrivate *priv;
3650
3651   g_return_if_fail (CLUTTER_IS_ACTOR (self));
3652   /* This should only be called from with in the ‘run’ implementation
3653      of a ClutterEffect */
3654   g_return_if_fail (CLUTTER_ACTOR_IN_PAINT (self));
3655
3656   priv = self->priv;
3657
3658   /* Skip any effects that are disabled */
3659   while (priv->next_effect_to_paint &&
3660          !clutter_actor_meta_get_enabled (priv->next_effect_to_paint->data))
3661     priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3662
3663   /* If this has come from the last effect then we'll just paint the
3664      actual actor */
3665   if (priv->next_effect_to_paint == NULL)
3666     {
3667       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3668         {
3669           ClutterPaintNode *dummy;
3670
3671           /* XXX - this will go away in 2.0, when we can get rid of this
3672            * stuff and switch to a pure retained render tree of PaintNodes
3673            * for the entire frame, starting from the Stage; the paint()
3674            * virtual function can then be called directly.
3675            */
3676           dummy = _clutter_dummy_node_new (self);
3677           clutter_paint_node_set_name (dummy, "Root");
3678
3679           /* XXX - for 1.12, we use the return value of paint_node() to
3680            * decide whether we should emit the ::paint signal.
3681            */
3682           clutter_actor_paint_node (self, dummy);
3683           clutter_paint_node_unref (dummy);
3684
3685           g_signal_emit (self, actor_signals[PAINT], 0);
3686         }
3687       else
3688         {
3689           ClutterColor col = { 0, };
3690
3691           _clutter_id_to_color (_clutter_actor_get_pick_id (self), &col);
3692
3693           /* Actor will then paint silhouette of itself in supplied
3694            * color.  See clutter_stage_get_actor_at_pos() for where
3695            * picking is enabled.
3696            */
3697           g_signal_emit (self, actor_signals[PICK], 0, &col);
3698         }
3699     }
3700   else
3701     {
3702       ClutterEffect *old_current_effect;
3703       ClutterEffectPaintFlags run_flags = 0;
3704
3705       /* Cache the current effect so that we can put it back before
3706          returning */
3707       old_current_effect = priv->current_effect;
3708
3709       priv->current_effect = priv->next_effect_to_paint->data;
3710       priv->next_effect_to_paint = priv->next_effect_to_paint->next;
3711
3712       if (_clutter_context_get_pick_mode () == CLUTTER_PICK_NONE)
3713         {
3714           if (priv->is_dirty)
3715             {
3716               /* If there's an effect queued with this redraw then all
3717                  effects up to that one will be considered dirty. It
3718                  is expected the queued effect will paint the cached
3719                  image and not call clutter_actor_continue_paint again
3720                  (although it should work ok if it does) */
3721               if (priv->effect_to_redraw == NULL ||
3722                   priv->current_effect != priv->effect_to_redraw)
3723                 run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3724             }
3725
3726           _clutter_effect_paint (priv->current_effect, run_flags);
3727         }
3728       else
3729         {
3730           /* We can't determine when an actor has been modified since
3731              its last pick so lets just assume it has always been
3732              modified */
3733           run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
3734
3735           _clutter_effect_pick (priv->current_effect, run_flags);
3736         }
3737
3738       priv->current_effect = old_current_effect;
3739     }
3740 }
3741
3742 static ClutterActorTraverseVisitFlags
3743 invalidate_queue_redraw_entry (ClutterActor *self,
3744                                int           depth,
3745                                gpointer      user_data)
3746 {
3747   ClutterActorPrivate *priv = self->priv;
3748
3749   if (priv->queue_redraw_entry != NULL)
3750     {
3751       _clutter_stage_queue_redraw_entry_invalidate (priv->queue_redraw_entry);
3752       priv->queue_redraw_entry = NULL;
3753     }
3754
3755   return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
3756 }
3757
3758 static inline void
3759 remove_child (ClutterActor *self,
3760               ClutterActor *child)
3761 {
3762   ClutterActor *prev_sibling, *next_sibling;
3763
3764   prev_sibling = child->priv->prev_sibling;
3765   next_sibling = child->priv->next_sibling;
3766
3767   if (prev_sibling != NULL)
3768     prev_sibling->priv->next_sibling = next_sibling;
3769
3770   if (next_sibling != NULL)
3771     next_sibling->priv->prev_sibling = prev_sibling;
3772
3773   if (self->priv->first_child == child)
3774     self->priv->first_child = next_sibling;
3775
3776   if (self->priv->last_child == child)
3777     self->priv->last_child = prev_sibling;
3778
3779   child->priv->parent = NULL;
3780   child->priv->prev_sibling = NULL;
3781   child->priv->next_sibling = NULL;
3782 }
3783
3784 typedef enum {
3785   REMOVE_CHILD_DESTROY_META       = 1 << 0,
3786   REMOVE_CHILD_EMIT_PARENT_SET    = 1 << 1,
3787   REMOVE_CHILD_EMIT_ACTOR_REMOVED = 1 << 2,
3788   REMOVE_CHILD_CHECK_STATE        = 1 << 3,
3789   REMOVE_CHILD_FLUSH_QUEUE        = 1 << 4,
3790   REMOVE_CHILD_NOTIFY_FIRST_LAST  = 1 << 5,
3791
3792   /* default flags for public API */
3793   REMOVE_CHILD_DEFAULT_FLAGS      = REMOVE_CHILD_DESTROY_META |
3794                                     REMOVE_CHILD_EMIT_PARENT_SET |
3795                                     REMOVE_CHILD_EMIT_ACTOR_REMOVED |
3796                                     REMOVE_CHILD_CHECK_STATE |
3797                                     REMOVE_CHILD_FLUSH_QUEUE |
3798                                     REMOVE_CHILD_NOTIFY_FIRST_LAST,
3799
3800   /* flags for legacy/deprecated API */
3801   REMOVE_CHILD_LEGACY_FLAGS       = REMOVE_CHILD_CHECK_STATE |
3802                                     REMOVE_CHILD_FLUSH_QUEUE |
3803                                     REMOVE_CHILD_EMIT_PARENT_SET |
3804                                     REMOVE_CHILD_NOTIFY_FIRST_LAST
3805 } ClutterActorRemoveChildFlags;
3806
3807 /*< private >
3808  * clutter_actor_remove_child_internal:
3809  * @self: a #ClutterActor
3810  * @child: the child of @self that has to be removed
3811  * @flags: control the removal operations
3812  *
3813  * Removes @child from the list of children of @self.
3814  */
3815 static void
3816 clutter_actor_remove_child_internal (ClutterActor                 *self,
3817                                      ClutterActor                 *child,
3818                                      ClutterActorRemoveChildFlags  flags)
3819 {
3820   ClutterActor *old_first, *old_last;
3821   gboolean destroy_meta, emit_parent_set, emit_actor_removed, check_state;
3822   gboolean flush_queue;
3823   gboolean notify_first_last;
3824   gboolean was_mapped;
3825
3826   destroy_meta = (flags & REMOVE_CHILD_DESTROY_META) != 0;
3827   emit_parent_set = (flags & REMOVE_CHILD_EMIT_PARENT_SET) != 0;
3828   emit_actor_removed = (flags & REMOVE_CHILD_EMIT_ACTOR_REMOVED) != 0;
3829   check_state = (flags & REMOVE_CHILD_CHECK_STATE) != 0;
3830   flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
3831   notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
3832
3833   g_object_freeze_notify (G_OBJECT (self));
3834
3835   if (destroy_meta)
3836     clutter_container_destroy_child_meta (CLUTTER_CONTAINER (self), child);
3837
3838   if (check_state)
3839     {
3840       was_mapped = CLUTTER_ACTOR_IS_MAPPED (child);
3841
3842       /* we need to unrealize *before* we set parent_actor to NULL,
3843        * because in an unrealize method actors are dissociating from the
3844        * stage, which means they need to be able to
3845        * clutter_actor_get_stage().
3846        *
3847        * yhis should unmap and unrealize, unless we're reparenting.
3848        */
3849       clutter_actor_update_map_state (child, MAP_STATE_MAKE_UNREALIZED);
3850     }
3851   else
3852     was_mapped = FALSE;
3853
3854   if (flush_queue)
3855     {
3856       /* We take this opportunity to invalidate any queue redraw entry
3857        * associated with the actor and descendants since we won't be able to
3858        * determine the appropriate stage after this.
3859        *
3860        * we do this after we updated the mapped state because actors might
3861        * end up queueing redraws inside their mapped/unmapped virtual
3862        * functions, and if we invalidate the redraw entry we could end up
3863        * with an inconsistent state and weird memory corruption. see
3864        * bugs:
3865        *
3866        *   http://bugzilla.clutter-project.org/show_bug.cgi?id=2621
3867        *   https://bugzilla.gnome.org/show_bug.cgi?id=652036
3868        */
3869       _clutter_actor_traverse (child,
3870                                0,
3871                                invalidate_queue_redraw_entry,
3872                                NULL,
3873                                NULL);
3874     }
3875
3876   old_first = self->priv->first_child;
3877   old_last = self->priv->last_child;
3878
3879   remove_child (self, child);
3880
3881   self->priv->n_children -= 1;
3882
3883   self->priv->age += 1;
3884
3885   /* clutter_actor_reparent() will emit ::parent-set for us */
3886   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
3887     g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
3888
3889   /* if the child was mapped then we need to relayout ourselves to account
3890    * for the removed child
3891    */
3892   if (was_mapped)
3893     clutter_actor_queue_relayout (self);
3894
3895   /* we need to emit the signal before dropping the reference */
3896   if (emit_actor_removed)
3897     g_signal_emit_by_name (self, "actor-removed", child);
3898
3899   if (notify_first_last)
3900     {
3901       if (old_first != self->priv->first_child)
3902         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
3903
3904       if (old_last != self->priv->last_child)
3905         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
3906     }
3907
3908   g_object_thaw_notify (G_OBJECT (self));
3909
3910   /* remove the reference we acquired in clutter_actor_add_child() */
3911   g_object_unref (child);
3912 }
3913
3914 static const ClutterTransformInfo default_transform_info = {
3915   0.0, { 0, },          /* rotation-x */
3916   0.0, { 0, },          /* rotation-y */
3917   0.0, { 0, },          /* rotation-z */
3918
3919   1.0, 1.0, { 0, },     /* scale */
3920
3921   { 0, },               /* anchor */
3922
3923   0.0,                  /* depth */
3924 };
3925
3926 /*< private >
3927  * _clutter_actor_get_transform_info_or_defaults:
3928  * @self: a #ClutterActor
3929  *
3930  * Retrieves the ClutterTransformInfo structure associated to an actor.
3931  *
3932  * If the actor does not have a ClutterTransformInfo structure associated
3933  * to it, then the default structure will be returned.
3934  *
3935  * This function should only be used for getters.
3936  *
3937  * Return value: a const pointer to the ClutterTransformInfo structure
3938  */
3939 const ClutterTransformInfo *
3940 _clutter_actor_get_transform_info_or_defaults (ClutterActor *self)
3941 {
3942   ClutterTransformInfo *info;
3943
3944   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3945   if (info != NULL)
3946     return info;
3947
3948   return &default_transform_info;
3949 }
3950
3951 static void
3952 clutter_transform_info_free (gpointer data)
3953 {
3954   if (data != NULL)
3955     g_slice_free (ClutterTransformInfo, data);
3956 }
3957
3958 /*< private >
3959  * _clutter_actor_get_transform_info:
3960  * @self: a #ClutterActor
3961  *
3962  * Retrieves a pointer to the ClutterTransformInfo structure.
3963  *
3964  * If the actor does not have a ClutterTransformInfo associated to it, one
3965  * will be created and initialized to the default values.
3966  *
3967  * This function should be used for setters.
3968  *
3969  * For getters, you should use _clutter_actor_get_transform_info_or_defaults()
3970  * instead.
3971  *
3972  * Return value: (transfer none): a pointer to the ClutterTransformInfo
3973  *   structure
3974  */
3975 ClutterTransformInfo *
3976 _clutter_actor_get_transform_info (ClutterActor *self)
3977 {
3978   ClutterTransformInfo *info;
3979
3980   info = g_object_get_qdata (G_OBJECT (self), quark_actor_transform_info);
3981   if (info == NULL)
3982     {
3983       info = g_slice_new (ClutterTransformInfo);
3984
3985       *info = default_transform_info;
3986
3987       g_object_set_qdata_full (G_OBJECT (self), quark_actor_transform_info,
3988                                info,
3989                                clutter_transform_info_free);
3990     }
3991
3992   return info;
3993 }
3994
3995 /*< private >
3996  * clutter_actor_set_rotation_angle_internal:
3997  * @self: a #ClutterActor
3998  * @axis: the axis of the angle to change
3999  * @angle: the angle of rotation
4000  *
4001  * Sets the rotation angle on the given axis without affecting the
4002  * rotation center point.
4003  */
4004 static inline void
4005 clutter_actor_set_rotation_angle_internal (ClutterActor      *self,
4006                                            ClutterRotateAxis  axis,
4007                                            gdouble            angle)
4008 {
4009   GObject *obj = G_OBJECT (self);
4010   ClutterTransformInfo *info;
4011
4012   info = _clutter_actor_get_transform_info (self);
4013
4014   g_object_freeze_notify (obj);
4015
4016   switch (axis)
4017     {
4018     case CLUTTER_X_AXIS:
4019       info->rx_angle = angle;
4020       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_X]);
4021       break;
4022
4023     case CLUTTER_Y_AXIS:
4024       info->ry_angle = angle;
4025       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Y]);
4026       break;
4027
4028     case CLUTTER_Z_AXIS:
4029       info->rz_angle = angle;
4030       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_ANGLE_Z]);
4031       break;
4032     }
4033
4034   self->priv->transform_valid = FALSE;
4035
4036   g_object_thaw_notify (obj);
4037
4038   clutter_actor_queue_redraw (self);
4039 }
4040
4041 static inline void
4042 clutter_actor_set_rotation_angle (ClutterActor      *self,
4043                                   ClutterRotateAxis  axis,
4044                                   gdouble            angle)
4045 {
4046   const ClutterTransformInfo *info;
4047   const double *cur_angle_p = NULL;
4048   GParamSpec *pspec = NULL;
4049
4050   info = _clutter_actor_get_transform_info_or_defaults (self);
4051
4052   switch (axis)
4053     {
4054     case CLUTTER_X_AXIS:
4055       cur_angle_p = &info->rx_angle;
4056       pspec = obj_props[PROP_ROTATION_ANGLE_X];
4057       break;
4058
4059     case CLUTTER_Y_AXIS:
4060       cur_angle_p = &info->ry_angle;
4061       pspec = obj_props[PROP_ROTATION_ANGLE_Y];
4062       break;
4063
4064     case CLUTTER_Z_AXIS:
4065       cur_angle_p = &info->rz_angle;
4066       pspec = obj_props[PROP_ROTATION_ANGLE_Z];
4067       break;
4068     }
4069
4070   g_assert (pspec != NULL);
4071   g_assert (cur_angle_p != NULL);
4072
4073   if (_clutter_actor_get_transition (self, pspec) == NULL)
4074     _clutter_actor_create_transition (self, pspec, *cur_angle_p, angle);
4075   else
4076     _clutter_actor_update_transition (self, pspec, angle);
4077
4078   clutter_actor_queue_redraw (self);
4079 }
4080
4081 /*< private >
4082  * clutter_actor_set_rotation_center_internal:
4083  * @self: a #ClutterActor
4084  * @axis: the axis of the center to change
4085  * @center: the coordinates of the rotation center
4086  *
4087  * Sets the rotation center on the given axis without affecting the
4088  * rotation angle.
4089  */
4090 static inline void
4091 clutter_actor_set_rotation_center_internal (ClutterActor        *self,
4092                                             ClutterRotateAxis    axis,
4093                                             const ClutterVertex *center)
4094 {
4095   GObject *obj = G_OBJECT (self);
4096   ClutterTransformInfo *info;
4097   ClutterVertex v = { 0, 0, 0 };
4098
4099   info = _clutter_actor_get_transform_info (self);
4100
4101   if (center != NULL)
4102     v = *center;
4103
4104   g_object_freeze_notify (obj);
4105
4106   switch (axis)
4107     {
4108     case CLUTTER_X_AXIS:
4109       clutter_anchor_coord_set_units (&info->rx_center, v.x, v.y, v.z);
4110       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_X]);
4111       break;
4112
4113     case CLUTTER_Y_AXIS:
4114       clutter_anchor_coord_set_units (&info->ry_center, v.x, v.y, v.z);
4115       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Y]);
4116       break;
4117
4118     case CLUTTER_Z_AXIS:
4119       /* if the previously set rotation center was fractional, then
4120        * setting explicit coordinates will have to notify the
4121        * :rotation-center-z-gravity property as well
4122        */
4123       if (info->rz_center.is_fractional)
4124         g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
4125
4126       clutter_anchor_coord_set_units (&info->rz_center, v.x, v.y, v.z);
4127       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
4128       break;
4129     }
4130
4131   self->priv->transform_valid = FALSE;
4132
4133   g_object_thaw_notify (obj);
4134
4135   clutter_actor_queue_redraw (self);
4136 }
4137
4138 static void
4139 clutter_actor_set_scale_factor_internal (ClutterActor *self,
4140                                          double factor,
4141                                          GParamSpec *pspec)
4142 {
4143   GObject *obj = G_OBJECT (self);
4144   ClutterTransformInfo *info;
4145
4146   info = _clutter_actor_get_transform_info (self);
4147
4148   if (pspec == obj_props[PROP_SCALE_X])
4149     info->scale_x = factor;
4150   else
4151     info->scale_y = factor;
4152
4153   self->priv->transform_valid = FALSE;
4154   clutter_actor_queue_redraw (self);
4155   g_object_notify_by_pspec (obj, pspec);
4156 }
4157
4158 static inline void
4159 clutter_actor_set_scale_factor (ClutterActor      *self,
4160                                 ClutterRotateAxis  axis,
4161                                 gdouble            factor)
4162 {
4163   const ClutterTransformInfo *info;
4164   const double *scale_p = NULL;
4165   GParamSpec *pspec = NULL;
4166
4167   info = _clutter_actor_get_transform_info_or_defaults (self);
4168
4169   switch (axis)
4170     {
4171     case CLUTTER_X_AXIS:
4172       pspec = obj_props[PROP_SCALE_X];
4173       scale_p = &info->scale_x;
4174       break;
4175
4176     case CLUTTER_Y_AXIS:
4177       pspec = obj_props[PROP_SCALE_Y];
4178       scale_p = &info->scale_y;
4179       break;
4180
4181     case CLUTTER_Z_AXIS:
4182       break;
4183     }
4184
4185   g_assert (pspec != NULL);
4186   g_assert (scale_p != NULL);
4187
4188   if (_clutter_actor_get_transition (self, pspec) == NULL)
4189     _clutter_actor_create_transition (self, pspec, *scale_p, factor);
4190   else
4191     _clutter_actor_update_transition (self, pspec, factor);
4192
4193   clutter_actor_queue_redraw (self);
4194 }
4195
4196 static inline void
4197 clutter_actor_set_scale_center (ClutterActor      *self,
4198                                 ClutterRotateAxis  axis,
4199                                 gfloat             coord)
4200 {
4201   GObject *obj = G_OBJECT (self);
4202   ClutterTransformInfo *info;
4203   gfloat center_x, center_y;
4204
4205   info = _clutter_actor_get_transform_info (self);
4206
4207   g_object_freeze_notify (obj);
4208
4209   /* get the current scale center coordinates */
4210   clutter_anchor_coord_get_units (self, &info->scale_center,
4211                                   &center_x,
4212                                   &center_y,
4213                                   NULL);
4214
4215   /* we need to notify this too, because setting explicit coordinates will
4216    * change the gravity as a side effect
4217    */
4218   if (info->scale_center.is_fractional)
4219     g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4220
4221   switch (axis)
4222     {
4223     case CLUTTER_X_AXIS:
4224       clutter_anchor_coord_set_units (&info->scale_center, coord, center_y, 0);
4225       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4226       break;
4227
4228     case CLUTTER_Y_AXIS:
4229       clutter_anchor_coord_set_units (&info->scale_center, center_x, coord, 0);
4230       g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4231       break;
4232
4233     default:
4234       g_assert_not_reached ();
4235     }
4236
4237   self->priv->transform_valid = FALSE;
4238
4239   clutter_actor_queue_redraw (self);
4240
4241   g_object_thaw_notify (obj);
4242 }
4243
4244 static inline void
4245 clutter_actor_set_scale_gravity (ClutterActor   *self,
4246                                  ClutterGravity  gravity)
4247 {
4248   ClutterTransformInfo *info;
4249   GObject *obj;
4250
4251   info = _clutter_actor_get_transform_info (self);
4252   obj = G_OBJECT (self);
4253
4254   if (gravity == CLUTTER_GRAVITY_NONE)
4255     clutter_anchor_coord_set_units (&info->scale_center, 0, 0, 0);
4256   else
4257     clutter_anchor_coord_set_gravity (&info->scale_center, gravity);
4258
4259   self->priv->transform_valid = FALSE;
4260
4261   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_X]);
4262   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_CENTER_Y]);
4263   g_object_notify_by_pspec (obj, obj_props[PROP_SCALE_GRAVITY]);
4264
4265   clutter_actor_queue_redraw (self);
4266 }
4267
4268 static inline void
4269 clutter_actor_set_anchor_coord (ClutterActor      *self,
4270                                 ClutterRotateAxis  axis,
4271                                 gfloat             coord)
4272 {
4273   GObject *obj = G_OBJECT (self);
4274   ClutterTransformInfo *info;
4275   gfloat anchor_x, anchor_y;
4276
4277   info = _clutter_actor_get_transform_info (self);
4278
4279   g_object_freeze_notify (obj);
4280
4281   clutter_anchor_coord_get_units (self, &info->anchor,
4282                                   &anchor_x,
4283                                   &anchor_y,
4284                                   NULL);
4285
4286   if (info->anchor.is_fractional)
4287     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
4288
4289   switch (axis)
4290     {
4291     case CLUTTER_X_AXIS:
4292       clutter_anchor_coord_set_units (&info->anchor,
4293                                       coord,
4294                                       anchor_y,
4295                                       0.0);
4296       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
4297       break;
4298
4299     case CLUTTER_Y_AXIS:
4300       clutter_anchor_coord_set_units (&info->anchor,
4301                                       anchor_x,
4302                                       coord,
4303                                       0.0);
4304       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
4305       break;
4306
4307     default:
4308       g_assert_not_reached ();
4309     }
4310
4311   self->priv->transform_valid = FALSE;
4312
4313   clutter_actor_queue_redraw (self);
4314
4315   g_object_thaw_notify (obj);
4316 }
4317
4318 static void
4319 clutter_actor_set_property (GObject      *object,
4320                             guint         prop_id,
4321                             const GValue *value,
4322                             GParamSpec   *pspec)
4323 {
4324   ClutterActor *actor = CLUTTER_ACTOR (object);
4325   ClutterActorPrivate *priv = actor->priv;
4326
4327   switch (prop_id)
4328     {
4329     case PROP_X:
4330       clutter_actor_set_x (actor, g_value_get_float (value));
4331       break;
4332
4333     case PROP_Y:
4334       clutter_actor_set_y (actor, g_value_get_float (value));
4335       break;
4336
4337     case PROP_WIDTH:
4338       clutter_actor_set_width (actor, g_value_get_float (value));
4339       break;
4340
4341     case PROP_HEIGHT:
4342       clutter_actor_set_height (actor, g_value_get_float (value));
4343       break;
4344
4345     case PROP_FIXED_X:
4346       clutter_actor_set_x (actor, g_value_get_float (value));
4347       break;
4348
4349     case PROP_FIXED_Y:
4350       clutter_actor_set_y (actor, g_value_get_float (value));
4351       break;
4352
4353     case PROP_FIXED_POSITION_SET:
4354       clutter_actor_set_fixed_position_set (actor, g_value_get_boolean (value));
4355       break;
4356
4357     case PROP_MIN_WIDTH:
4358       clutter_actor_set_min_width (actor, g_value_get_float (value));
4359       break;
4360
4361     case PROP_MIN_HEIGHT:
4362       clutter_actor_set_min_height (actor, g_value_get_float (value));
4363       break;
4364
4365     case PROP_NATURAL_WIDTH:
4366       clutter_actor_set_natural_width (actor, g_value_get_float (value));
4367       break;
4368
4369     case PROP_NATURAL_HEIGHT:
4370       clutter_actor_set_natural_height (actor, g_value_get_float (value));
4371       break;
4372
4373     case PROP_MIN_WIDTH_SET:
4374       clutter_actor_set_min_width_set (actor, g_value_get_boolean (value));
4375       break;
4376
4377     case PROP_MIN_HEIGHT_SET:
4378       clutter_actor_set_min_height_set (actor, g_value_get_boolean (value));
4379       break;
4380
4381     case PROP_NATURAL_WIDTH_SET:
4382       clutter_actor_set_natural_width_set (actor, g_value_get_boolean (value));
4383       break;
4384
4385     case PROP_NATURAL_HEIGHT_SET:
4386       clutter_actor_set_natural_height_set (actor, g_value_get_boolean (value));
4387       break;
4388
4389     case PROP_REQUEST_MODE:
4390       clutter_actor_set_request_mode (actor, g_value_get_enum (value));
4391       break;
4392
4393     case PROP_DEPTH:
4394       clutter_actor_set_depth (actor, g_value_get_float (value));
4395       break;
4396
4397     case PROP_OPACITY:
4398       clutter_actor_set_opacity (actor, g_value_get_uint (value));
4399       break;
4400
4401     case PROP_OFFSCREEN_REDIRECT:
4402       clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
4403       break;
4404
4405     case PROP_NAME:
4406       clutter_actor_set_name (actor, g_value_get_string (value));
4407       break;
4408
4409     case PROP_VISIBLE:
4410       if (g_value_get_boolean (value) == TRUE)
4411         clutter_actor_show (actor);
4412       else
4413         clutter_actor_hide (actor);
4414       break;
4415
4416     case PROP_SCALE_X:
4417       clutter_actor_set_scale_factor (actor, CLUTTER_X_AXIS,
4418                                       g_value_get_double (value));
4419       break;
4420
4421     case PROP_SCALE_Y:
4422       clutter_actor_set_scale_factor (actor, CLUTTER_Y_AXIS,
4423                                       g_value_get_double (value));
4424       break;
4425
4426     case PROP_SCALE_CENTER_X:
4427       clutter_actor_set_scale_center (actor, CLUTTER_X_AXIS,
4428                                       g_value_get_float (value));
4429       break;
4430
4431     case PROP_SCALE_CENTER_Y:
4432       clutter_actor_set_scale_center (actor, CLUTTER_Y_AXIS,
4433                                       g_value_get_float (value));
4434       break;
4435
4436     case PROP_SCALE_GRAVITY:
4437       clutter_actor_set_scale_gravity (actor, g_value_get_enum (value));
4438       break;
4439
4440     case PROP_CLIP:
4441       {
4442         const ClutterGeometry *geom = g_value_get_boxed (value);
4443
4444         clutter_actor_set_clip (actor,
4445                                 geom->x, geom->y,
4446                                 geom->width, geom->height);
4447       }
4448       break;
4449
4450     case PROP_CLIP_TO_ALLOCATION:
4451       clutter_actor_set_clip_to_allocation (actor, g_value_get_boolean (value));
4452       break;
4453
4454     case PROP_REACTIVE:
4455       clutter_actor_set_reactive (actor, g_value_get_boolean (value));
4456       break;
4457
4458     case PROP_ROTATION_ANGLE_X:
4459       clutter_actor_set_rotation_angle (actor,
4460                                         CLUTTER_X_AXIS,
4461                                         g_value_get_double (value));
4462       break;
4463
4464     case PROP_ROTATION_ANGLE_Y:
4465       clutter_actor_set_rotation_angle (actor,
4466                                         CLUTTER_Y_AXIS,
4467                                         g_value_get_double (value));
4468       break;
4469
4470     case PROP_ROTATION_ANGLE_Z:
4471       clutter_actor_set_rotation_angle (actor,
4472                                         CLUTTER_Z_AXIS,
4473                                         g_value_get_double (value));
4474       break;
4475
4476     case PROP_ROTATION_CENTER_X:
4477       clutter_actor_set_rotation_center_internal (actor,
4478                                                   CLUTTER_X_AXIS,
4479                                                   g_value_get_boxed (value));
4480       break;
4481
4482     case PROP_ROTATION_CENTER_Y:
4483       clutter_actor_set_rotation_center_internal (actor,
4484                                                   CLUTTER_Y_AXIS,
4485                                                   g_value_get_boxed (value));
4486       break;
4487
4488     case PROP_ROTATION_CENTER_Z:
4489       clutter_actor_set_rotation_center_internal (actor,
4490                                                   CLUTTER_Z_AXIS,
4491                                                   g_value_get_boxed (value));
4492       break;
4493
4494     case PROP_ROTATION_CENTER_Z_GRAVITY:
4495       {
4496         const ClutterTransformInfo *info;
4497
4498         info = _clutter_actor_get_transform_info_or_defaults (actor);
4499         clutter_actor_set_z_rotation_from_gravity (actor, info->rz_angle,
4500                                                    g_value_get_enum (value));
4501       }
4502       break;
4503
4504     case PROP_ANCHOR_X:
4505       clutter_actor_set_anchor_coord (actor, CLUTTER_X_AXIS,
4506                                       g_value_get_float (value));
4507       break;
4508
4509     case PROP_ANCHOR_Y:
4510       clutter_actor_set_anchor_coord (actor, CLUTTER_Y_AXIS,
4511                                       g_value_get_float (value));
4512       break;
4513
4514     case PROP_ANCHOR_GRAVITY:
4515       clutter_actor_set_anchor_point_from_gravity (actor,
4516                                                    g_value_get_enum (value));
4517       break;
4518
4519     case PROP_SHOW_ON_SET_PARENT:
4520       priv->show_on_set_parent = g_value_get_boolean (value);
4521       break;
4522
4523     case PROP_TEXT_DIRECTION:
4524       clutter_actor_set_text_direction (actor, g_value_get_enum (value));
4525       break;
4526
4527     case PROP_ACTIONS:
4528       clutter_actor_add_action (actor, g_value_get_object (value));
4529       break;
4530
4531     case PROP_CONSTRAINTS:
4532       clutter_actor_add_constraint (actor, g_value_get_object (value));
4533       break;
4534
4535     case PROP_EFFECT:
4536       clutter_actor_add_effect (actor, g_value_get_object (value));
4537       break;
4538
4539     case PROP_LAYOUT_MANAGER:
4540       clutter_actor_set_layout_manager (actor, g_value_get_object (value));
4541       break;
4542
4543     case PROP_X_ALIGN:
4544       clutter_actor_set_x_align (actor, g_value_get_enum (value));
4545       break;
4546
4547     case PROP_Y_ALIGN:
4548       clutter_actor_set_y_align (actor, g_value_get_enum (value));
4549       break;
4550
4551     case PROP_MARGIN_TOP:
4552       clutter_actor_set_margin_top (actor, g_value_get_float (value));
4553       break;
4554
4555     case PROP_MARGIN_BOTTOM:
4556       clutter_actor_set_margin_bottom (actor, g_value_get_float (value));
4557       break;
4558
4559     case PROP_MARGIN_LEFT:
4560       clutter_actor_set_margin_left (actor, g_value_get_float (value));
4561       break;
4562
4563     case PROP_MARGIN_RIGHT:
4564       clutter_actor_set_margin_right (actor, g_value_get_float (value));
4565       break;
4566
4567     case PROP_BACKGROUND_COLOR:
4568       clutter_actor_set_background_color (actor, g_value_get_boxed (value));
4569       break;
4570
4571     case PROP_CONTENT:
4572       clutter_actor_set_content (actor, g_value_get_object (value));
4573       break;
4574
4575     case PROP_CONTENT_GRAVITY:
4576       clutter_actor_set_content_gravity (actor, g_value_get_enum (value));
4577       break;
4578
4579     case PROP_MINIFICATION_FILTER:
4580       clutter_actor_set_content_scaling_filters (actor,
4581                                                  g_value_get_enum (value),
4582                                                  actor->priv->mag_filter);
4583       break;
4584
4585     case PROP_MAGNIFICATION_FILTER:
4586       clutter_actor_set_content_scaling_filters (actor,
4587                                                  actor->priv->min_filter,
4588                                                  g_value_get_enum (value));
4589       break;
4590
4591     default:
4592       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
4593       break;
4594     }
4595 }
4596
4597 static void
4598 clutter_actor_get_property (GObject    *object,
4599                             guint       prop_id,
4600                             GValue     *value,
4601                             GParamSpec *pspec)
4602 {
4603   ClutterActor *actor = CLUTTER_ACTOR (object);
4604   ClutterActorPrivate *priv = actor->priv;
4605
4606   switch (prop_id)
4607     {
4608     case PROP_X:
4609       g_value_set_float (value, clutter_actor_get_x (actor));
4610       break;
4611
4612     case PROP_Y:
4613       g_value_set_float (value, clutter_actor_get_y (actor));
4614       break;
4615
4616     case PROP_WIDTH:
4617       g_value_set_float (value, clutter_actor_get_width (actor));
4618       break;
4619
4620     case PROP_HEIGHT:
4621       g_value_set_float (value, clutter_actor_get_height (actor));
4622       break;
4623
4624     case PROP_FIXED_X:
4625       {
4626         const ClutterLayoutInfo *info;
4627
4628         info = _clutter_actor_get_layout_info_or_defaults (actor);
4629         g_value_set_float (value, info->fixed_x);
4630       }
4631       break;
4632
4633     case PROP_FIXED_Y:
4634       {
4635         const ClutterLayoutInfo *info;
4636
4637         info = _clutter_actor_get_layout_info_or_defaults (actor);
4638         g_value_set_float (value, info->fixed_y);
4639       }
4640       break;
4641
4642     case PROP_FIXED_POSITION_SET:
4643       g_value_set_boolean (value, priv->position_set);
4644       break;
4645
4646     case PROP_MIN_WIDTH:
4647       {
4648         const ClutterLayoutInfo *info;
4649
4650         info = _clutter_actor_get_layout_info_or_defaults (actor);
4651         g_value_set_float (value, info->min_width);
4652       }
4653       break;
4654
4655     case PROP_MIN_HEIGHT:
4656       {
4657         const ClutterLayoutInfo *info;
4658
4659         info = _clutter_actor_get_layout_info_or_defaults (actor);
4660         g_value_set_float (value, info->min_height);
4661       }
4662       break;
4663
4664     case PROP_NATURAL_WIDTH:
4665       {
4666         const ClutterLayoutInfo *info;
4667
4668         info = _clutter_actor_get_layout_info_or_defaults (actor);
4669         g_value_set_float (value, info->natural_width);
4670       }
4671       break;
4672
4673     case PROP_NATURAL_HEIGHT:
4674       {
4675         const ClutterLayoutInfo *info;
4676
4677         info = _clutter_actor_get_layout_info_or_defaults (actor);
4678         g_value_set_float (value, info->natural_height);
4679       }
4680       break;
4681
4682     case PROP_MIN_WIDTH_SET:
4683       g_value_set_boolean (value, priv->min_width_set);
4684       break;
4685
4686     case PROP_MIN_HEIGHT_SET:
4687       g_value_set_boolean (value, priv->min_height_set);
4688       break;
4689
4690     case PROP_NATURAL_WIDTH_SET:
4691       g_value_set_boolean (value, priv->natural_width_set);
4692       break;
4693
4694     case PROP_NATURAL_HEIGHT_SET:
4695       g_value_set_boolean (value, priv->natural_height_set);
4696       break;
4697
4698     case PROP_REQUEST_MODE:
4699       g_value_set_enum (value, priv->request_mode);
4700       break;
4701
4702     case PROP_ALLOCATION:
4703       g_value_set_boxed (value, &priv->allocation);
4704       break;
4705
4706     case PROP_DEPTH:
4707       g_value_set_float (value, clutter_actor_get_depth (actor));
4708       break;
4709
4710     case PROP_OPACITY:
4711       g_value_set_uint (value, priv->opacity);
4712       break;
4713
4714     case PROP_OFFSCREEN_REDIRECT:
4715       g_value_set_enum (value, priv->offscreen_redirect);
4716       break;
4717
4718     case PROP_NAME:
4719       g_value_set_string (value, priv->name);
4720       break;
4721
4722     case PROP_VISIBLE:
4723       g_value_set_boolean (value, CLUTTER_ACTOR_IS_VISIBLE (actor));
4724       break;
4725
4726     case PROP_MAPPED:
4727       g_value_set_boolean (value, CLUTTER_ACTOR_IS_MAPPED (actor));
4728       break;
4729
4730     case PROP_REALIZED:
4731       g_value_set_boolean (value, CLUTTER_ACTOR_IS_REALIZED (actor));
4732       break;
4733
4734     case PROP_HAS_CLIP:
4735       g_value_set_boolean (value, priv->has_clip);
4736       break;
4737
4738     case PROP_CLIP:
4739       {
4740         ClutterGeometry clip;
4741
4742         clip.x      = CLUTTER_NEARBYINT (priv->clip.x);
4743         clip.y      = CLUTTER_NEARBYINT (priv->clip.y);
4744         clip.width  = CLUTTER_NEARBYINT (priv->clip.width);
4745         clip.height = CLUTTER_NEARBYINT (priv->clip.height);
4746
4747         g_value_set_boxed (value, &clip);
4748       }
4749       break;
4750
4751     case PROP_CLIP_TO_ALLOCATION:
4752       g_value_set_boolean (value, priv->clip_to_allocation);
4753       break;
4754
4755     case PROP_SCALE_X:
4756       {
4757         const ClutterTransformInfo *info;
4758
4759         info = _clutter_actor_get_transform_info_or_defaults (actor);
4760         g_value_set_double (value, info->scale_x);
4761       }
4762       break;
4763
4764     case PROP_SCALE_Y:
4765       {
4766         const ClutterTransformInfo *info;
4767
4768         info = _clutter_actor_get_transform_info_or_defaults (actor);
4769         g_value_set_double (value, info->scale_y);
4770       }
4771       break;
4772
4773     case PROP_SCALE_CENTER_X:
4774       {
4775         gfloat center;
4776
4777         clutter_actor_get_scale_center (actor, &center, NULL);
4778
4779         g_value_set_float (value, center);
4780       }
4781       break;
4782
4783     case PROP_SCALE_CENTER_Y:
4784       {
4785         gfloat center;
4786
4787         clutter_actor_get_scale_center (actor, NULL, &center);
4788
4789         g_value_set_float (value, center);
4790       }
4791       break;
4792
4793     case PROP_SCALE_GRAVITY:
4794       g_value_set_enum (value, clutter_actor_get_scale_gravity (actor));
4795       break;
4796
4797     case PROP_REACTIVE:
4798       g_value_set_boolean (value, clutter_actor_get_reactive (actor));
4799       break;
4800
4801     case PROP_ROTATION_ANGLE_X:
4802       {
4803         const ClutterTransformInfo *info;
4804
4805         info = _clutter_actor_get_transform_info_or_defaults (actor);
4806         g_value_set_double (value, info->rx_angle);
4807       }
4808       break;
4809
4810     case PROP_ROTATION_ANGLE_Y:
4811       {
4812         const ClutterTransformInfo *info;
4813
4814         info = _clutter_actor_get_transform_info_or_defaults (actor);
4815         g_value_set_double (value, info->ry_angle);
4816       }
4817       break;
4818
4819     case PROP_ROTATION_ANGLE_Z:
4820       {
4821         const ClutterTransformInfo *info;
4822
4823         info = _clutter_actor_get_transform_info_or_defaults (actor);
4824         g_value_set_double (value, info->rz_angle);
4825       }
4826       break;
4827
4828     case PROP_ROTATION_CENTER_X:
4829       {
4830         ClutterVertex center;
4831
4832         clutter_actor_get_rotation (actor, CLUTTER_X_AXIS,
4833                                     &center.x,
4834                                     &center.y,
4835                                     &center.z);
4836
4837         g_value_set_boxed (value, &center);
4838       }
4839       break;
4840
4841     case PROP_ROTATION_CENTER_Y:
4842       {
4843         ClutterVertex center;
4844
4845         clutter_actor_get_rotation (actor, CLUTTER_Y_AXIS,
4846                                     &center.x,
4847                                     &center.y,
4848                                     &center.z);
4849
4850         g_value_set_boxed (value, &center);
4851       }
4852       break;
4853
4854     case PROP_ROTATION_CENTER_Z:
4855       {
4856         ClutterVertex center;
4857
4858         clutter_actor_get_rotation (actor, CLUTTER_Z_AXIS,
4859                                     &center.x,
4860                                     &center.y,
4861                                     &center.z);
4862
4863         g_value_set_boxed (value, &center);
4864       }
4865       break;
4866
4867     case PROP_ROTATION_CENTER_Z_GRAVITY:
4868       g_value_set_enum (value, clutter_actor_get_z_rotation_gravity (actor));
4869       break;
4870
4871     case PROP_ANCHOR_X:
4872       {
4873         const ClutterTransformInfo *info;
4874         gfloat anchor_x;
4875
4876         info = _clutter_actor_get_transform_info_or_defaults (actor);
4877         clutter_anchor_coord_get_units (actor, &info->anchor,
4878                                         &anchor_x,
4879                                         NULL,
4880                                         NULL);
4881         g_value_set_float (value, anchor_x);
4882       }
4883       break;
4884
4885     case PROP_ANCHOR_Y:
4886       {
4887         const ClutterTransformInfo *info;
4888         gfloat anchor_y;
4889
4890         info = _clutter_actor_get_transform_info_or_defaults (actor);
4891         clutter_anchor_coord_get_units (actor, &info->anchor,
4892                                         NULL,
4893                                         &anchor_y,
4894                                         NULL);
4895         g_value_set_float (value, anchor_y);
4896       }
4897       break;
4898
4899     case PROP_ANCHOR_GRAVITY:
4900       g_value_set_enum (value, clutter_actor_get_anchor_point_gravity (actor));
4901       break;
4902
4903     case PROP_SHOW_ON_SET_PARENT:
4904       g_value_set_boolean (value, priv->show_on_set_parent);
4905       break;
4906
4907     case PROP_TEXT_DIRECTION:
4908       g_value_set_enum (value, priv->text_direction);
4909       break;
4910
4911     case PROP_HAS_POINTER:
4912       g_value_set_boolean (value, priv->has_pointer);
4913       break;
4914
4915     case PROP_LAYOUT_MANAGER:
4916       g_value_set_object (value, priv->layout_manager);
4917       break;
4918
4919     case PROP_X_ALIGN:
4920       {
4921         const ClutterLayoutInfo *info;
4922
4923         info = _clutter_actor_get_layout_info_or_defaults (actor);
4924         g_value_set_enum (value, info->x_align);
4925       }
4926       break;
4927
4928     case PROP_Y_ALIGN:
4929       {
4930         const ClutterLayoutInfo *info;
4931
4932         info = _clutter_actor_get_layout_info_or_defaults (actor);
4933         g_value_set_enum (value, info->y_align);
4934       }
4935       break;
4936
4937     case PROP_MARGIN_TOP:
4938       {
4939         const ClutterLayoutInfo *info;
4940
4941         info = _clutter_actor_get_layout_info_or_defaults (actor);
4942         g_value_set_float (value, info->margin.top);
4943       }
4944       break;
4945
4946     case PROP_MARGIN_BOTTOM:
4947       {
4948         const ClutterLayoutInfo *info;
4949
4950         info = _clutter_actor_get_layout_info_or_defaults (actor);
4951         g_value_set_float (value, info->margin.bottom);
4952       }
4953       break;
4954
4955     case PROP_MARGIN_LEFT:
4956       {
4957         const ClutterLayoutInfo *info;
4958
4959         info = _clutter_actor_get_layout_info_or_defaults (actor);
4960         g_value_set_float (value, info->margin.left);
4961       }
4962       break;
4963
4964     case PROP_MARGIN_RIGHT:
4965       {
4966         const ClutterLayoutInfo *info;
4967
4968         info = _clutter_actor_get_layout_info_or_defaults (actor);
4969         g_value_set_float (value, info->margin.right);
4970       }
4971       break;
4972
4973     case PROP_BACKGROUND_COLOR_SET:
4974       g_value_set_boolean (value, priv->bg_color_set);
4975       break;
4976
4977     case PROP_BACKGROUND_COLOR:
4978       g_value_set_boxed (value, &priv->bg_color);
4979       break;
4980
4981     case PROP_FIRST_CHILD:
4982       g_value_set_object (value, priv->first_child);
4983       break;
4984
4985     case PROP_LAST_CHILD:
4986       g_value_set_object (value, priv->last_child);
4987       break;
4988
4989     case PROP_CONTENT:
4990       g_value_set_object (value, priv->content);
4991       break;
4992
4993     case PROP_CONTENT_GRAVITY:
4994       g_value_set_enum (value, priv->content_gravity);
4995       break;
4996
4997     case PROP_CONTENT_BOX:
4998       {
4999         ClutterActorBox box = { 0, };
5000
5001         clutter_actor_get_content_box (actor, &box);
5002         g_value_set_boxed (value, &box);
5003       }
5004       break;
5005
5006     case PROP_MINIFICATION_FILTER:
5007       g_value_set_enum (value, priv->min_filter);
5008       break;
5009
5010     case PROP_MAGNIFICATION_FILTER:
5011       g_value_set_enum (value, priv->mag_filter);
5012       break;
5013
5014     default:
5015       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
5016       break;
5017     }
5018 }
5019
5020 static void
5021 clutter_actor_dispose (GObject *object)
5022 {
5023   ClutterActor *self = CLUTTER_ACTOR (object);
5024   ClutterActorPrivate *priv = self->priv;
5025
5026   CLUTTER_NOTE (MISC, "Disposing of object (id=%d) of type '%s' (ref_count:%d)",
5027                 priv->id,
5028                 g_type_name (G_OBJECT_TYPE (self)),
5029                 object->ref_count);
5030
5031   g_signal_emit (self, actor_signals[DESTROY], 0);
5032
5033   /* avoid recursing when called from clutter_actor_destroy() */
5034   if (priv->parent != NULL)
5035     {
5036       ClutterActor *parent = priv->parent;
5037
5038       /* go through the Container implementation unless this
5039        * is an internal child and has been marked as such.
5040        *
5041        * removing the actor from its parent will reset the
5042        * realized and mapped states.
5043        */
5044       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
5045         clutter_container_remove_actor (CLUTTER_CONTAINER (parent), self);
5046       else
5047         clutter_actor_remove_child_internal (parent, self,
5048                                              REMOVE_CHILD_LEGACY_FLAGS);
5049     }
5050
5051   /* parent must be gone at this point */
5052   g_assert (priv->parent == NULL);
5053
5054   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
5055     {
5056       /* can't be mapped or realized with no parent */
5057       g_assert (!CLUTTER_ACTOR_IS_MAPPED (self));
5058       g_assert (!CLUTTER_ACTOR_IS_REALIZED (self));
5059     }
5060
5061   g_clear_object (&priv->pango_context);
5062   g_clear_object (&priv->actions);
5063   g_clear_object (&priv->constraints);
5064   g_clear_object (&priv->effects);
5065   g_clear_object (&priv->flatten_effect);
5066
5067   if (priv->layout_manager != NULL)
5068     {
5069       clutter_layout_manager_set_container (priv->layout_manager, NULL);
5070       g_clear_object (&priv->layout_manager);
5071     }
5072
5073   if (priv->content != NULL)
5074     {
5075       _clutter_content_detached (priv->content, self);
5076       g_clear_object (&priv->content);
5077     }
5078
5079   G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
5080 }
5081
5082 static void
5083 clutter_actor_finalize (GObject *object)
5084 {
5085   ClutterActorPrivate *priv = CLUTTER_ACTOR (object)->priv;
5086
5087   CLUTTER_NOTE (MISC, "Finalize actor (name='%s', id=%d) of type '%s'",
5088                 priv->name != NULL ? priv->name : "<none>",
5089                 priv->id,
5090                 g_type_name (G_OBJECT_TYPE (object)));
5091
5092   _clutter_context_release_id (priv->id);
5093
5094   g_free (priv->name);
5095
5096   G_OBJECT_CLASS (clutter_actor_parent_class)->finalize (object);
5097 }
5098
5099
5100 /**
5101  * clutter_actor_get_accessible:
5102  * @self: a #ClutterActor
5103  *
5104  * Returns the accessible object that describes the actor to an
5105  * assistive technology.
5106  *
5107  * If no class-specific #AtkObject implementation is available for the
5108  * actor instance in question, it will inherit an #AtkObject
5109  * implementation from the first ancestor class for which such an
5110  * implementation is defined.
5111  *
5112  * The documentation of the <ulink
5113  * url="http://developer.gnome.org/doc/API/2.0/atk/index.html">ATK</ulink>
5114  * library contains more information about accessible objects and
5115  * their uses.
5116  *
5117  * Returns: (transfer none): the #AtkObject associated with @actor
5118  */
5119 AtkObject *
5120 clutter_actor_get_accessible (ClutterActor *self)
5121 {
5122   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5123
5124   return CLUTTER_ACTOR_GET_CLASS (self)->get_accessible (self);
5125 }
5126
5127 static AtkObject *
5128 clutter_actor_real_get_accessible (ClutterActor *actor)
5129 {
5130   return atk_gobject_accessible_for_object (G_OBJECT (actor));
5131 }
5132
5133 static AtkObject *
5134 _clutter_actor_ref_accessible (AtkImplementor *implementor)
5135 {
5136   AtkObject *accessible;
5137
5138   accessible = clutter_actor_get_accessible (CLUTTER_ACTOR (implementor));
5139   if (accessible != NULL)
5140     g_object_ref (accessible);
5141
5142   return accessible;
5143 }
5144
5145 static void
5146 atk_implementor_iface_init (AtkImplementorIface *iface)
5147 {
5148   iface->ref_accessible = _clutter_actor_ref_accessible;
5149 }
5150
5151 static gboolean
5152 clutter_actor_update_default_paint_volume (ClutterActor       *self,
5153                                            ClutterPaintVolume *volume)
5154 {
5155   ClutterActorPrivate *priv = self->priv;
5156   gboolean res = FALSE;
5157
5158   /* we start from the allocation */
5159   clutter_paint_volume_set_width (volume,
5160                                   priv->allocation.x2 - priv->allocation.x1);
5161   clutter_paint_volume_set_height (volume,
5162                                    priv->allocation.y2 - priv->allocation.y1);
5163
5164   /* if the actor has a clip set then we have a pretty definite
5165    * size for the paint volume: the actor cannot possibly paint
5166    * outside the clip region.
5167    */
5168   if (priv->clip_to_allocation)
5169     {
5170       /* the allocation has already been set, so we just flip the
5171        * return value
5172        */
5173       res = TRUE;
5174     }
5175   else
5176     {
5177       ClutterActor *child;
5178
5179       if (priv->has_clip &&
5180           priv->clip.width >= 0 &&
5181           priv->clip.height >= 0)
5182         {
5183           ClutterVertex origin;
5184
5185           origin.x = priv->clip.x;
5186           origin.y = priv->clip.y;
5187           origin.z = 0;
5188
5189           clutter_paint_volume_set_origin (volume, &origin);
5190           clutter_paint_volume_set_width (volume, priv->clip.width);
5191           clutter_paint_volume_set_height (volume, priv->clip.height);
5192
5193           res = TRUE;
5194         }
5195
5196       /* if we don't have children we just bail out here... */
5197       if (priv->n_children == 0)
5198         return res;
5199
5200       /* ...but if we have children then we ask for their paint volume in
5201        * our coordinates. if any of our children replies that it doesn't
5202        * have a paint volume, we bail out
5203        */
5204       for (child = priv->first_child;
5205            child != NULL;
5206            child = child->priv->next_sibling)
5207         {
5208           const ClutterPaintVolume *child_volume;
5209
5210           child_volume = clutter_actor_get_transformed_paint_volume (child, self);
5211           if (child_volume == NULL)
5212             {
5213               res = FALSE;
5214               break;
5215             }
5216
5217           clutter_paint_volume_union (volume, child_volume);
5218           res = TRUE;
5219         }
5220     }
5221
5222   return res;
5223
5224 }
5225
5226 static gboolean
5227 clutter_actor_real_get_paint_volume (ClutterActor       *self,
5228                                      ClutterPaintVolume *volume)
5229 {
5230   ClutterActorClass *klass;
5231   gboolean res;
5232
5233   klass = CLUTTER_ACTOR_GET_CLASS (self);
5234
5235   /* XXX - this thoroughly sucks, but we don't want to penalize users
5236    * who use ClutterActor as a "new ClutterGroup" by forcing a full-stage
5237    * redraw. This should go away in 2.0.
5238    */
5239   if (klass->paint == clutter_actor_real_paint &&
5240       klass->get_paint_volume == clutter_actor_real_get_paint_volume)
5241     {
5242       res = TRUE;
5243     }
5244   else
5245     {
5246       /* this is the default return value: we cannot know if a class
5247        * is going to paint outside its allocation, so we take the
5248        * conservative approach.
5249        */
5250       res = FALSE;
5251     }
5252
5253   if (clutter_actor_update_default_paint_volume (self, volume))
5254     return res;
5255
5256   return FALSE;
5257 }
5258
5259 /**
5260  * clutter_actor_get_default_paint_volume:
5261  * @self: a #ClutterActor
5262  *
5263  * Retrieves the default paint volume for @self.
5264  *
5265  * This function provides the same #ClutterPaintVolume that would be
5266  * computed by the default implementation inside #ClutterActor of the
5267  * #ClutterActorClass.get_paint_volume() virtual function.
5268  *
5269  * This function should only be used by #ClutterActor subclasses that
5270  * cannot chain up to the parent implementation when computing their
5271  * paint volume.
5272  *
5273  * Return value: (transfer none): a pointer to the default
5274  *   #ClutterPaintVolume, relative to the #ClutterActor, or %NULL if
5275  *   the actor could not compute a valid paint volume. The returned value
5276  *   is not guaranteed to be stable across multiple frames, so if you
5277  *   want to retain it, you will need to copy it using
5278  *   clutter_paint_volume_copy().
5279  *
5280  * Since: 1.10
5281  */
5282 const ClutterPaintVolume *
5283 clutter_actor_get_default_paint_volume (ClutterActor *self)
5284 {
5285   ClutterPaintVolume volume;
5286   ClutterPaintVolume *res;
5287
5288   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
5289
5290   res = NULL;
5291   _clutter_paint_volume_init_static (&volume, self);
5292   if (clutter_actor_update_default_paint_volume (self, &volume))
5293     {
5294       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
5295
5296       if (stage != NULL)
5297         {
5298           res = _clutter_stage_paint_volume_stack_allocate (CLUTTER_STAGE (stage));
5299           _clutter_paint_volume_copy_static (&volume, res);
5300         }
5301     }
5302
5303   clutter_paint_volume_free (&volume);
5304
5305   return res;
5306 }
5307
5308 static gboolean
5309 clutter_actor_real_has_overlaps (ClutterActor *self)
5310 {
5311   /* By default we'll assume that all actors need an offscreen redirect to get
5312    * the correct opacity. Actors such as ClutterTexture that would never need
5313    * an offscreen redirect can override this to return FALSE. */
5314   return TRUE;
5315 }
5316
5317 static void
5318 clutter_actor_real_destroy (ClutterActor *actor)
5319 {
5320   ClutterActorIter iter;
5321
5322   g_object_freeze_notify (G_OBJECT (actor));
5323
5324   clutter_actor_iter_init (&iter, actor);
5325   while (clutter_actor_iter_next (&iter, NULL))
5326     clutter_actor_iter_destroy (&iter);
5327
5328   g_object_thaw_notify (G_OBJECT (actor));
5329 }
5330
5331 static GObject *
5332 clutter_actor_constructor (GType gtype,
5333                            guint n_props,
5334                            GObjectConstructParam *props)
5335 {
5336   GObjectClass *gobject_class;
5337   ClutterActor *self;
5338   GObject *retval;
5339
5340   gobject_class = G_OBJECT_CLASS (clutter_actor_parent_class);
5341   retval = gobject_class->constructor (gtype, n_props, props);
5342   self = CLUTTER_ACTOR (retval);
5343
5344   if (self->priv->layout_manager == NULL)
5345     {
5346       ClutterLayoutManager *default_layout;
5347
5348       CLUTTER_NOTE (LAYOUT, "Creating default layout manager");
5349
5350       default_layout = clutter_fixed_layout_new ();
5351       clutter_actor_set_layout_manager (self, default_layout);
5352     }
5353
5354   return retval;
5355 }
5356
5357 static void
5358 clutter_actor_class_init (ClutterActorClass *klass)
5359 {
5360   GObjectClass *object_class = G_OBJECT_CLASS (klass);
5361
5362   quark_shader_data = g_quark_from_static_string ("-clutter-actor-shader-data");
5363   quark_actor_layout_info = g_quark_from_static_string ("-clutter-actor-layout-info");
5364   quark_actor_transform_info = g_quark_from_static_string ("-clutter-actor-transform-info");
5365   quark_actor_animation_info = g_quark_from_static_string ("-clutter-actor-animation-info");
5366
5367   object_class->constructor = clutter_actor_constructor;
5368   object_class->set_property = clutter_actor_set_property;
5369   object_class->get_property = clutter_actor_get_property;
5370   object_class->dispose = clutter_actor_dispose;
5371   object_class->finalize = clutter_actor_finalize;
5372
5373   klass->show = clutter_actor_real_show;
5374   klass->show_all = clutter_actor_show;
5375   klass->hide = clutter_actor_real_hide;
5376   klass->hide_all = clutter_actor_hide;
5377   klass->map = clutter_actor_real_map;
5378   klass->unmap = clutter_actor_real_unmap;
5379   klass->unrealize = clutter_actor_real_unrealize;
5380   klass->pick = clutter_actor_real_pick;
5381   klass->get_preferred_width = clutter_actor_real_get_preferred_width;
5382   klass->get_preferred_height = clutter_actor_real_get_preferred_height;
5383   klass->allocate = clutter_actor_real_allocate;
5384   klass->queue_redraw = clutter_actor_real_queue_redraw;
5385   klass->queue_relayout = clutter_actor_real_queue_relayout;
5386   klass->apply_transform = clutter_actor_real_apply_transform;
5387   klass->get_accessible = clutter_actor_real_get_accessible;
5388   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
5389   klass->has_overlaps = clutter_actor_real_has_overlaps;
5390   klass->paint = clutter_actor_real_paint;
5391   klass->destroy = clutter_actor_real_destroy;
5392
5393   g_type_class_add_private (klass, sizeof (ClutterActorPrivate));
5394
5395   /**
5396    * ClutterActor:x:
5397    *
5398    * X coordinate of the actor in pixels. If written, forces a fixed
5399    * position for the actor. If read, returns the fixed position if any,
5400    * otherwise the allocation if available, otherwise 0.
5401    *
5402    * The #ClutterActor:x property is animatable.
5403    */
5404   obj_props[PROP_X] =
5405     g_param_spec_float ("x",
5406                         P_("X coordinate"),
5407                         P_("X coordinate of the actor"),
5408                         -G_MAXFLOAT, G_MAXFLOAT,
5409                         0.0,
5410                         G_PARAM_READWRITE |
5411                         G_PARAM_STATIC_STRINGS |
5412                         CLUTTER_PARAM_ANIMATABLE);
5413
5414   /**
5415    * ClutterActor:y:
5416    *
5417    * Y coordinate of the actor in pixels. If written, forces a fixed
5418    * position for the actor.  If read, returns the fixed position if
5419    * any, otherwise the allocation if available, otherwise 0.
5420    *
5421    * The #ClutterActor:y property is animatable.
5422    */
5423   obj_props[PROP_Y] =
5424     g_param_spec_float ("y",
5425                         P_("Y coordinate"),
5426                         P_("Y coordinate of the actor"),
5427                         -G_MAXFLOAT, G_MAXFLOAT,
5428                         0.0,
5429                         G_PARAM_READWRITE |
5430                         G_PARAM_STATIC_STRINGS |
5431                         CLUTTER_PARAM_ANIMATABLE);
5432
5433   /**
5434    * ClutterActor:width:
5435    *
5436    * Width of the actor (in pixels). If written, forces the minimum and
5437    * natural size request of the actor to the given width. If read, returns
5438    * the allocated width if available, otherwise the width request.
5439    *
5440    * The #ClutterActor:width property is animatable.
5441    */
5442   obj_props[PROP_WIDTH] =
5443     g_param_spec_float ("width",
5444                         P_("Width"),
5445                         P_("Width of the actor"),
5446                         0.0, G_MAXFLOAT,
5447                         0.0,
5448                         G_PARAM_READWRITE |
5449                         G_PARAM_STATIC_STRINGS |
5450                         CLUTTER_PARAM_ANIMATABLE);
5451
5452   /**
5453    * ClutterActor:height:
5454    *
5455    * Height of the actor (in pixels).  If written, forces the minimum and
5456    * natural size request of the actor to the given height. If read, returns
5457    * the allocated height if available, otherwise the height request.
5458    *
5459    * The #ClutterActor:height property is animatable.
5460    */
5461   obj_props[PROP_HEIGHT] =
5462     g_param_spec_float ("height",
5463                         P_("Height"),
5464                         P_("Height of the actor"),
5465                         0.0, G_MAXFLOAT,
5466                         0.0,
5467                         G_PARAM_READWRITE |
5468                         G_PARAM_STATIC_STRINGS |
5469                         CLUTTER_PARAM_ANIMATABLE);
5470
5471   /**
5472    * ClutterActor:fixed-x:
5473    *
5474    * The fixed X position of the actor in pixels.
5475    *
5476    * Writing this property sets #ClutterActor:fixed-position-set
5477    * property as well, as a side effect
5478    *
5479    * Since: 0.8
5480    */
5481   obj_props[PROP_FIXED_X] =
5482     g_param_spec_float ("fixed-x",
5483                         P_("Fixed X"),
5484                         P_("Forced X position of the actor"),
5485                         -G_MAXFLOAT, G_MAXFLOAT,
5486                         0.0,
5487                         CLUTTER_PARAM_READWRITE);
5488
5489   /**
5490    * ClutterActor:fixed-y:
5491    *
5492    * The fixed Y position of the actor in pixels.
5493    *
5494    * Writing this property sets the #ClutterActor:fixed-position-set
5495    * property as well, as a side effect
5496    *
5497    * Since: 0.8
5498    */
5499   obj_props[PROP_FIXED_Y] =
5500     g_param_spec_float ("fixed-y",
5501                         P_("Fixed Y"),
5502                         P_("Forced Y position of the actor"),
5503                         -G_MAXFLOAT, G_MAXFLOAT,
5504                         0,
5505                         CLUTTER_PARAM_READWRITE);
5506
5507   /**
5508    * ClutterActor:fixed-position-set:
5509    *
5510    * This flag controls whether the #ClutterActor:fixed-x and
5511    * #ClutterActor:fixed-y properties are used
5512    *
5513    * Since: 0.8
5514    */
5515   obj_props[PROP_FIXED_POSITION_SET] =
5516     g_param_spec_boolean ("fixed-position-set",
5517                           P_("Fixed position set"),
5518                           P_("Whether to use fixed positioning for the actor"),
5519                           FALSE,
5520                           CLUTTER_PARAM_READWRITE);
5521
5522   /**
5523    * ClutterActor:min-width:
5524    *
5525    * A forced minimum width request for the actor, in pixels
5526    *
5527    * Writing this property sets the #ClutterActor:min-width-set property
5528    * as well, as a side effect.
5529    *
5530    *This property overrides the usual width request of the actor.
5531    *
5532    * Since: 0.8
5533    */
5534   obj_props[PROP_MIN_WIDTH] =
5535     g_param_spec_float ("min-width",
5536                         P_("Min Width"),
5537                         P_("Forced minimum width request for the actor"),
5538                         0.0, G_MAXFLOAT,
5539                         0.0,
5540                         CLUTTER_PARAM_READWRITE);
5541
5542   /**
5543    * ClutterActor:min-height:
5544    *
5545    * A forced minimum height request for the actor, in pixels
5546    *
5547    * Writing this property sets the #ClutterActor:min-height-set property
5548    * as well, as a side effect. This property overrides the usual height
5549    * request of the actor.
5550    *
5551    * Since: 0.8
5552    */
5553   obj_props[PROP_MIN_HEIGHT] =
5554     g_param_spec_float ("min-height",
5555                         P_("Min Height"),
5556                         P_("Forced minimum height request for the actor"),
5557                         0.0, G_MAXFLOAT,
5558                         0.0,
5559                         CLUTTER_PARAM_READWRITE);
5560
5561   /**
5562    * ClutterActor:natural-width:
5563    *
5564    * A forced natural width request for the actor, in pixels
5565    *
5566    * Writing this property sets the #ClutterActor:natural-width-set
5567    * property as well, as a side effect. This property overrides the
5568    * usual width request of the actor
5569    *
5570    * Since: 0.8
5571    */
5572   obj_props[PROP_NATURAL_WIDTH] =
5573     g_param_spec_float ("natural-width",
5574                         P_("Natural Width"),
5575                         P_("Forced natural width request for the actor"),
5576                         0.0, G_MAXFLOAT,
5577                         0.0,
5578                         CLUTTER_PARAM_READWRITE);
5579
5580   /**
5581    * ClutterActor:natural-height:
5582    *
5583    * A forced natural height request for the actor, in pixels
5584    *
5585    * Writing this property sets the #ClutterActor:natural-height-set
5586    * property as well, as a side effect. This property overrides the
5587    * usual height request of the actor
5588    *
5589    * Since: 0.8
5590    */
5591   obj_props[PROP_NATURAL_HEIGHT] =
5592     g_param_spec_float ("natural-height",
5593                         P_("Natural Height"),
5594                         P_("Forced natural height request for the actor"),
5595                         0.0, G_MAXFLOAT,
5596                         0.0,
5597                         CLUTTER_PARAM_READWRITE);
5598
5599   /**
5600    * ClutterActor:min-width-set:
5601    *
5602    * This flag controls whether the #ClutterActor:min-width property
5603    * is used
5604    *
5605    * Since: 0.8
5606    */
5607   obj_props[PROP_MIN_WIDTH_SET] =
5608     g_param_spec_boolean ("min-width-set",
5609                           P_("Minimum width set"),
5610                           P_("Whether to use the min-width property"),
5611                           FALSE,
5612                           CLUTTER_PARAM_READWRITE);
5613
5614   /**
5615    * ClutterActor:min-height-set:
5616    *
5617    * This flag controls whether the #ClutterActor:min-height property
5618    * is used
5619    *
5620    * Since: 0.8
5621    */
5622   obj_props[PROP_MIN_HEIGHT_SET] =
5623     g_param_spec_boolean ("min-height-set",
5624                           P_("Minimum height set"),
5625                           P_("Whether to use the min-height property"),
5626                           FALSE,
5627                           CLUTTER_PARAM_READWRITE);
5628
5629   /**
5630    * ClutterActor:natural-width-set:
5631    *
5632    * This flag controls whether the #ClutterActor:natural-width property
5633    * is used
5634    *
5635    * Since: 0.8
5636    */
5637   obj_props[PROP_NATURAL_WIDTH_SET] =
5638     g_param_spec_boolean ("natural-width-set",
5639                           P_("Natural width set"),
5640                           P_("Whether to use the natural-width property"),
5641                           FALSE,
5642                           CLUTTER_PARAM_READWRITE);
5643
5644   /**
5645    * ClutterActor:natural-height-set:
5646    *
5647    * This flag controls whether the #ClutterActor:natural-height property
5648    * is used
5649    *
5650    * Since: 0.8
5651    */
5652   obj_props[PROP_NATURAL_HEIGHT_SET] =
5653     g_param_spec_boolean ("natural-height-set",
5654                           P_("Natural height set"),
5655                           P_("Whether to use the natural-height property"),
5656                           FALSE,
5657                           CLUTTER_PARAM_READWRITE);
5658
5659   /**
5660    * ClutterActor:allocation:
5661    *
5662    * The allocation for the actor, in pixels
5663    *
5664    * This is property is read-only, but you might monitor it to know when an
5665    * actor moves or resizes
5666    *
5667    * Since: 0.8
5668    */
5669   obj_props[PROP_ALLOCATION] =
5670     g_param_spec_boxed ("allocation",
5671                         P_("Allocation"),
5672                         P_("The actor's allocation"),
5673                         CLUTTER_TYPE_ACTOR_BOX,
5674                         CLUTTER_PARAM_READABLE);
5675
5676   /**
5677    * ClutterActor:request-mode:
5678    *
5679    * Request mode for the #ClutterActor. The request mode determines the
5680    * type of geometry management used by the actor, either height for width
5681    * (the default) or width for height.
5682    *
5683    * For actors implementing height for width, the parent container should get
5684    * the preferred width first, and then the preferred height for that width.
5685    *
5686    * For actors implementing width for height, the parent container should get
5687    * the preferred height first, and then the preferred width for that height.
5688    *
5689    * For instance:
5690    *
5691    * |[
5692    *   ClutterRequestMode mode;
5693    *   gfloat natural_width, min_width;
5694    *   gfloat natural_height, min_height;
5695    *
5696    *   mode = clutter_actor_get_request_mode (child);
5697    *   if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
5698    *     {
5699    *       clutter_actor_get_preferred_width (child, -1,
5700    *                                          &amp;min_width,
5701    *                                          &amp;natural_width);
5702    *       clutter_actor_get_preferred_height (child, natural_width,
5703    *                                           &amp;min_height,
5704    *                                           &amp;natural_height);
5705    *     }
5706    *   else
5707    *     {
5708    *       clutter_actor_get_preferred_height (child, -1,
5709    *                                           &amp;min_height,
5710    *                                           &amp;natural_height);
5711    *       clutter_actor_get_preferred_width (child, natural_height,
5712    *                                          &amp;min_width,
5713    *                                          &amp;natural_width);
5714    *     }
5715    * ]|
5716    *
5717    * will retrieve the minimum and natural width and height depending on the
5718    * preferred request mode of the #ClutterActor "child".
5719    *
5720    * The clutter_actor_get_preferred_size() function will implement this
5721    * check for you.
5722    *
5723    * Since: 0.8
5724    */
5725   obj_props[PROP_REQUEST_MODE] =
5726     g_param_spec_enum ("request-mode",
5727                        P_("Request Mode"),
5728                        P_("The actor's request mode"),
5729                        CLUTTER_TYPE_REQUEST_MODE,
5730                        CLUTTER_REQUEST_HEIGHT_FOR_WIDTH,
5731                        CLUTTER_PARAM_READWRITE);
5732
5733   /**
5734    * ClutterActor:depth:
5735    *
5736    * The position of the actor on the Z axis.
5737    *
5738    * The #ClutterActor:depth property is relative to the parent's
5739    * modelview matrix.
5740    *
5741    * The #ClutterActor:depth property is animatable.
5742    *
5743    * Since: 0.6
5744    */
5745   obj_props[PROP_DEPTH] =
5746     g_param_spec_float ("depth",
5747                         P_("Depth"),
5748                         P_("Position on the Z axis"),
5749                         -G_MAXFLOAT, G_MAXFLOAT,
5750                         0.0,
5751                         G_PARAM_READWRITE |
5752                         G_PARAM_STATIC_STRINGS |
5753                         CLUTTER_PARAM_ANIMATABLE);
5754
5755   /**
5756    * ClutterActor:opacity:
5757    *
5758    * Opacity of an actor, between 0 (fully transparent) and
5759    * 255 (fully opaque)
5760    *
5761    * The #ClutterActor:opacity property is animatable.
5762    */
5763   obj_props[PROP_OPACITY] =
5764     g_param_spec_uint ("opacity",
5765                        P_("Opacity"),
5766                        P_("Opacity of an actor"),
5767                        0, 255,
5768                        255,
5769                        G_PARAM_READWRITE |
5770                        G_PARAM_STATIC_STRINGS |
5771                        CLUTTER_PARAM_ANIMATABLE);
5772
5773   /**
5774    * ClutterActor:offscreen-redirect:
5775    *
5776    * Determines the conditions in which the actor will be redirected
5777    * to an offscreen framebuffer while being painted. For example this
5778    * can be used to cache an actor in a framebuffer or for improved
5779    * handling of transparent actors. See
5780    * clutter_actor_set_offscreen_redirect() for details.
5781    *
5782    * Since: 1.8
5783    */
5784   obj_props[PROP_OFFSCREEN_REDIRECT] =
5785     g_param_spec_flags ("offscreen-redirect",
5786                         P_("Offscreen redirect"),
5787                         P_("Flags controlling when to flatten the actor into a single image"),
5788                         CLUTTER_TYPE_OFFSCREEN_REDIRECT,
5789                         0,
5790                         CLUTTER_PARAM_READWRITE);
5791
5792   /**
5793    * ClutterActor:visible:
5794    *
5795    * Whether the actor is set to be visible or not
5796    *
5797    * See also #ClutterActor:mapped
5798    */
5799   obj_props[PROP_VISIBLE] =
5800     g_param_spec_boolean ("visible",
5801                           P_("Visible"),
5802                           P_("Whether the actor is visible or not"),
5803                           FALSE,
5804                           CLUTTER_PARAM_READWRITE);
5805
5806   /**
5807    * ClutterActor:mapped:
5808    *
5809    * Whether the actor is mapped (will be painted when the stage
5810    * to which it belongs is mapped)
5811    *
5812    * Since: 1.0
5813    */
5814   obj_props[PROP_MAPPED] =
5815     g_param_spec_boolean ("mapped",
5816                           P_("Mapped"),
5817                           P_("Whether the actor will be painted"),
5818                           FALSE,
5819                           CLUTTER_PARAM_READABLE);
5820
5821   /**
5822    * ClutterActor:realized:
5823    *
5824    * Whether the actor has been realized
5825    *
5826    * Since: 1.0
5827    */
5828   obj_props[PROP_REALIZED] =
5829     g_param_spec_boolean ("realized",
5830                           P_("Realized"),
5831                           P_("Whether the actor has been realized"),
5832                           FALSE,
5833                           CLUTTER_PARAM_READABLE);
5834
5835   /**
5836    * ClutterActor:reactive:
5837    *
5838    * Whether the actor is reactive to events or not
5839    *
5840    * Only reactive actors will emit event-related signals
5841    *
5842    * Since: 0.6
5843    */
5844   obj_props[PROP_REACTIVE] =
5845     g_param_spec_boolean ("reactive",
5846                           P_("Reactive"),
5847                           P_("Whether the actor is reactive to events"),
5848                           FALSE,
5849                           CLUTTER_PARAM_READWRITE);
5850
5851   /**
5852    * ClutterActor:has-clip:
5853    *
5854    * Whether the actor has the #ClutterActor:clip property set or not
5855    */
5856   obj_props[PROP_HAS_CLIP] =
5857     g_param_spec_boolean ("has-clip",
5858                           P_("Has Clip"),
5859                           P_("Whether the actor has a clip set"),
5860                           FALSE,
5861                           CLUTTER_PARAM_READABLE);
5862
5863   /**
5864    * ClutterActor:clip:
5865    *
5866    * The clip region for the actor, in actor-relative coordinates
5867    *
5868    * Every part of the actor outside the clip region will not be
5869    * painted
5870    */
5871   obj_props[PROP_CLIP] =
5872     g_param_spec_boxed ("clip",
5873                         P_("Clip"),
5874                         P_("The clip region for the actor"),
5875                         CLUTTER_TYPE_GEOMETRY,
5876                         CLUTTER_PARAM_READWRITE);
5877
5878   /**
5879    * ClutterActor:name:
5880    *
5881    * The name of the actor
5882    *
5883    * Since: 0.2
5884    */
5885   obj_props[PROP_NAME] =
5886     g_param_spec_string ("name",
5887                          P_("Name"),
5888                          P_("Name of the actor"),
5889                          NULL,
5890                          CLUTTER_PARAM_READWRITE);
5891
5892   /**
5893    * ClutterActor:scale-x:
5894    *
5895    * The horizontal scale of the actor.
5896    *
5897    * The #ClutterActor:scale-x property is animatable.
5898    *
5899    * Since: 0.6
5900    */
5901   obj_props[PROP_SCALE_X] =
5902     g_param_spec_double ("scale-x",
5903                          P_("Scale X"),
5904                          P_("Scale factor on the X axis"),
5905                          0.0, G_MAXDOUBLE,
5906                          1.0,
5907                          G_PARAM_READWRITE |
5908                          G_PARAM_STATIC_STRINGS |
5909                          CLUTTER_PARAM_ANIMATABLE);
5910
5911   /**
5912    * ClutterActor:scale-y:
5913    *
5914    * The vertical scale of the actor.
5915    *
5916    * The #ClutterActor:scale-y property is animatable.
5917    *
5918    * Since: 0.6
5919    */
5920   obj_props[PROP_SCALE_Y] =
5921     g_param_spec_double ("scale-y",
5922                          P_("Scale Y"),
5923                          P_("Scale factor on the Y axis"),
5924                          0.0, G_MAXDOUBLE,
5925                          1.0,
5926                          G_PARAM_READWRITE |
5927                          G_PARAM_STATIC_STRINGS |
5928                          CLUTTER_PARAM_ANIMATABLE);
5929
5930   /**
5931    * ClutterActor:scale-center-x:
5932    *
5933    * The horizontal center point for scaling
5934    *
5935    * Since: 1.0
5936    */
5937   obj_props[PROP_SCALE_CENTER_X] =
5938     g_param_spec_float ("scale-center-x",
5939                         P_("Scale Center X"),
5940                         P_("Horizontal scale center"),
5941                         -G_MAXFLOAT, G_MAXFLOAT,
5942                         0.0,
5943                         CLUTTER_PARAM_READWRITE);
5944
5945   /**
5946    * ClutterActor:scale-center-y:
5947    *
5948    * The vertical center point for scaling
5949    *
5950    * Since: 1.0
5951    */
5952   obj_props[PROP_SCALE_CENTER_Y] =
5953     g_param_spec_float ("scale-center-y",
5954                         P_("Scale Center Y"),
5955                         P_("Vertical scale center"),
5956                         -G_MAXFLOAT, G_MAXFLOAT,
5957                         0.0,
5958                         CLUTTER_PARAM_READWRITE);
5959
5960   /**
5961    * ClutterActor:scale-gravity:
5962    *
5963    * The center point for scaling expressed as a #ClutterGravity
5964    *
5965    * Since: 1.0
5966    */
5967   obj_props[PROP_SCALE_GRAVITY] =
5968     g_param_spec_enum ("scale-gravity",
5969                        P_("Scale Gravity"),
5970                        P_("The center of scaling"),
5971                        CLUTTER_TYPE_GRAVITY,
5972                        CLUTTER_GRAVITY_NONE,
5973                        CLUTTER_PARAM_READWRITE);
5974
5975   /**
5976    * ClutterActor:rotation-angle-x:
5977    *
5978    * The rotation angle on the X axis.
5979    *
5980    * The #ClutterActor:rotation-angle-x property is animatable.
5981    *
5982    * Since: 0.6
5983    */
5984   obj_props[PROP_ROTATION_ANGLE_X] =
5985     g_param_spec_double ("rotation-angle-x",
5986                          P_("Rotation Angle X"),
5987                          P_("The rotation angle on the X axis"),
5988                          -G_MAXDOUBLE, G_MAXDOUBLE,
5989                          0.0,
5990                          G_PARAM_READWRITE |
5991                          G_PARAM_STATIC_STRINGS |
5992                          CLUTTER_PARAM_ANIMATABLE);
5993
5994   /**
5995    * ClutterActor:rotation-angle-y:
5996    *
5997    * The rotation angle on the Y axis
5998    *
5999    * The #ClutterActor:rotation-angle-y property is animatable.
6000    *
6001    * Since: 0.6
6002    */
6003   obj_props[PROP_ROTATION_ANGLE_Y] =
6004     g_param_spec_double ("rotation-angle-y",
6005                          P_("Rotation Angle Y"),
6006                          P_("The rotation angle on the Y axis"),
6007                          -G_MAXDOUBLE, G_MAXDOUBLE,
6008                          0.0,
6009                          G_PARAM_READWRITE |
6010                          G_PARAM_STATIC_STRINGS |
6011                          CLUTTER_PARAM_ANIMATABLE);
6012
6013   /**
6014    * ClutterActor:rotation-angle-z:
6015    *
6016    * The rotation angle on the Z axis
6017    *
6018    * The #ClutterActor:rotation-angle-z property is animatable.
6019    *
6020    * Since: 0.6
6021    */
6022   obj_props[PROP_ROTATION_ANGLE_Z] =
6023     g_param_spec_double ("rotation-angle-z",
6024                          P_("Rotation Angle Z"),
6025                          P_("The rotation angle on the Z axis"),
6026                          -G_MAXDOUBLE, G_MAXDOUBLE,
6027                          0.0,
6028                          G_PARAM_READWRITE |
6029                          G_PARAM_STATIC_STRINGS |
6030                          CLUTTER_PARAM_ANIMATABLE);
6031
6032   /**
6033    * ClutterActor:rotation-center-x:
6034    *
6035    * The rotation center on the X axis.
6036    *
6037    * Since: 0.6
6038    */
6039   obj_props[PROP_ROTATION_CENTER_X] =
6040     g_param_spec_boxed ("rotation-center-x",
6041                         P_("Rotation Center X"),
6042                         P_("The rotation center on the X axis"),
6043                         CLUTTER_TYPE_VERTEX,
6044                         CLUTTER_PARAM_READWRITE);
6045
6046   /**
6047    * ClutterActor:rotation-center-y:
6048    *
6049    * The rotation center on the Y axis.
6050    *
6051    * Since: 0.6
6052    */
6053   obj_props[PROP_ROTATION_CENTER_Y] =
6054     g_param_spec_boxed ("rotation-center-y",
6055                         P_("Rotation Center Y"),
6056                         P_("The rotation center on the Y axis"),
6057                         CLUTTER_TYPE_VERTEX,
6058                         CLUTTER_PARAM_READWRITE);
6059
6060   /**
6061    * ClutterActor:rotation-center-z:
6062    *
6063    * The rotation center on the Z axis.
6064    *
6065    * Since: 0.6
6066    */
6067   obj_props[PROP_ROTATION_CENTER_Z] =
6068     g_param_spec_boxed ("rotation-center-z",
6069                         P_("Rotation Center Z"),
6070                         P_("The rotation center on the Z axis"),
6071                         CLUTTER_TYPE_VERTEX,
6072                         CLUTTER_PARAM_READWRITE);
6073
6074   /**
6075    * ClutterActor:rotation-center-z-gravity:
6076    *
6077    * The rotation center on the Z axis expressed as a #ClutterGravity.
6078    *
6079    * Since: 1.0
6080    */
6081   obj_props[PROP_ROTATION_CENTER_Z_GRAVITY] =
6082     g_param_spec_enum ("rotation-center-z-gravity",
6083                        P_("Rotation Center Z Gravity"),
6084                        P_("Center point for rotation around the Z axis"),
6085                        CLUTTER_TYPE_GRAVITY,
6086                        CLUTTER_GRAVITY_NONE,
6087                        CLUTTER_PARAM_READWRITE);
6088
6089   /**
6090    * ClutterActor:anchor-x:
6091    *
6092    * The X coordinate of an actor's anchor point, relative to
6093    * the actor coordinate space, in pixels
6094    *
6095    * Since: 0.8
6096    */
6097   obj_props[PROP_ANCHOR_X] =
6098     g_param_spec_float ("anchor-x",
6099                         P_("Anchor X"),
6100                         P_("X coordinate of the anchor point"),
6101                         -G_MAXFLOAT, G_MAXFLOAT,
6102                         0,
6103                         CLUTTER_PARAM_READWRITE);
6104
6105   /**
6106    * ClutterActor:anchor-y:
6107    *
6108    * The Y coordinate of an actor's anchor point, relative to
6109    * the actor coordinate space, in pixels
6110    *
6111    * Since: 0.8
6112    */
6113   obj_props[PROP_ANCHOR_Y] =
6114     g_param_spec_float ("anchor-y",
6115                         P_("Anchor Y"),
6116                         P_("Y coordinate of the anchor point"),
6117                         -G_MAXFLOAT, G_MAXFLOAT,
6118                         0,
6119                         CLUTTER_PARAM_READWRITE);
6120
6121   /**
6122    * ClutterActor:anchor-gravity:
6123    *
6124    * The anchor point expressed as a #ClutterGravity
6125    *
6126    * Since: 1.0
6127    */
6128   obj_props[PROP_ANCHOR_GRAVITY] =
6129     g_param_spec_enum ("anchor-gravity",
6130                        P_("Anchor Gravity"),
6131                        P_("The anchor point as a ClutterGravity"),
6132                        CLUTTER_TYPE_GRAVITY,
6133                        CLUTTER_GRAVITY_NONE,
6134                        CLUTTER_PARAM_READWRITE);
6135
6136   /**
6137    * ClutterActor:show-on-set-parent:
6138    *
6139    * If %TRUE, the actor is automatically shown when parented.
6140    *
6141    * Calling clutter_actor_hide() on an actor which has not been
6142    * parented will set this property to %FALSE as a side effect.
6143    *
6144    * Since: 0.8
6145    */
6146   obj_props[PROP_SHOW_ON_SET_PARENT] =
6147     g_param_spec_boolean ("show-on-set-parent",
6148                           P_("Show on set parent"),
6149                           P_("Whether the actor is shown when parented"),
6150                           TRUE,
6151                           CLUTTER_PARAM_READWRITE);
6152
6153   /**
6154    * ClutterActor:clip-to-allocation:
6155    *
6156    * Whether the clip region should track the allocated area
6157    * of the actor.
6158    *
6159    * This property is ignored if a clip area has been explicitly
6160    * set using clutter_actor_set_clip().
6161    *
6162    * Since: 1.0
6163    */
6164   obj_props[PROP_CLIP_TO_ALLOCATION] =
6165     g_param_spec_boolean ("clip-to-allocation",
6166                           P_("Clip to Allocation"),
6167                           P_("Sets the clip region to track the actor's allocation"),
6168                           FALSE,
6169                           CLUTTER_PARAM_READWRITE);
6170
6171   /**
6172    * ClutterActor:text-direction:
6173    *
6174    * The direction of the text inside a #ClutterActor.
6175    *
6176    * Since: 1.0
6177    */
6178   obj_props[PROP_TEXT_DIRECTION] =
6179     g_param_spec_enum ("text-direction",
6180                        P_("Text Direction"),
6181                        P_("Direction of the text"),
6182                        CLUTTER_TYPE_TEXT_DIRECTION,
6183                        CLUTTER_TEXT_DIRECTION_LTR,
6184                        CLUTTER_PARAM_READWRITE);
6185
6186   /**
6187    * ClutterActor:has-pointer:
6188    *
6189    * Whether the actor contains the pointer of a #ClutterInputDevice
6190    * or not.
6191    *
6192    * Since: 1.2
6193    */
6194   obj_props[PROP_HAS_POINTER] =
6195     g_param_spec_boolean ("has-pointer",
6196                           P_("Has Pointer"),
6197                           P_("Whether the actor contains the pointer of an input device"),
6198                           FALSE,
6199                           CLUTTER_PARAM_READABLE);
6200
6201   /**
6202    * ClutterActor:actions:
6203    *
6204    * Adds a #ClutterAction to the actor
6205    *
6206    * Since: 1.4
6207    */
6208   obj_props[PROP_ACTIONS] =
6209     g_param_spec_object ("actions",
6210                          P_("Actions"),
6211                          P_("Adds an action to the actor"),
6212                          CLUTTER_TYPE_ACTION,
6213                          CLUTTER_PARAM_WRITABLE);
6214
6215   /**
6216    * ClutterActor:constraints:
6217    *
6218    * Adds a #ClutterConstraint to the actor
6219    *
6220    * Since: 1.4
6221    */
6222   obj_props[PROP_CONSTRAINTS] =
6223     g_param_spec_object ("constraints",
6224                          P_("Constraints"),
6225                          P_("Adds a constraint to the actor"),
6226                          CLUTTER_TYPE_CONSTRAINT,
6227                          CLUTTER_PARAM_WRITABLE);
6228
6229   /**
6230    * ClutterActor:effect:
6231    *
6232    * Adds #ClutterEffect to the list of effects be applied on a #ClutterActor
6233    *
6234    * Since: 1.4
6235    */
6236   obj_props[PROP_EFFECT] =
6237     g_param_spec_object ("effect",
6238                          P_("Effect"),
6239                          P_("Add an effect to be applied on the actor"),
6240                          CLUTTER_TYPE_EFFECT,
6241                          CLUTTER_PARAM_WRITABLE);
6242
6243   /**
6244    * ClutterActor:layout-manager:
6245    *
6246    * A delegate object for controlling the layout of the children of
6247    * an actor.
6248    *
6249    * Since: 1.10
6250    */
6251   obj_props[PROP_LAYOUT_MANAGER] =
6252     g_param_spec_object ("layout-manager",
6253                          P_("Layout Manager"),
6254                          P_("The object controlling the layout of an actor's children"),
6255                          CLUTTER_TYPE_LAYOUT_MANAGER,
6256                          CLUTTER_PARAM_READWRITE);
6257
6258
6259   /**
6260    * ClutterActor:x-align:
6261    *
6262    * The alignment of an actor on the X axis, if the actor has been given
6263    * extra space for its allocation.
6264    *
6265    * Since: 1.10
6266    */
6267   obj_props[PROP_X_ALIGN] =
6268     g_param_spec_enum ("x-align",
6269                        P_("X Alignment"),
6270                        P_("The alignment of the actor on the X axis within its allocation"),
6271                        CLUTTER_TYPE_ACTOR_ALIGN,
6272                        CLUTTER_ACTOR_ALIGN_FILL,
6273                        CLUTTER_PARAM_READWRITE);
6274
6275   /**
6276    * ClutterActor:y-align:
6277    *
6278    * The alignment of an actor on the Y axis, if the actor has been given
6279    * extra space for its allocation.
6280    *
6281    * Since: 1.10
6282    */
6283   obj_props[PROP_Y_ALIGN] =
6284     g_param_spec_enum ("y-align",
6285                        P_("Y Alignment"),
6286                        P_("The alignment of the actor on the Y axis within its allocation"),
6287                        CLUTTER_TYPE_ACTOR_ALIGN,
6288                        CLUTTER_ACTOR_ALIGN_FILL,
6289                        CLUTTER_PARAM_READWRITE);
6290
6291   /**
6292    * ClutterActor:margin-top:
6293    *
6294    * The margin (in pixels) from the top of the actor.
6295    *
6296    * This property adds a margin to the actor's preferred size; the margin
6297    * will be automatically taken into account when allocating the actor.
6298    *
6299    * Since: 1.10
6300    */
6301   obj_props[PROP_MARGIN_TOP] =
6302     g_param_spec_float ("margin-top",
6303                         P_("Margin Top"),
6304                         P_("Extra space at the top"),
6305                         0.0, G_MAXFLOAT,
6306                         0.0,
6307                         CLUTTER_PARAM_READWRITE);
6308
6309   /**
6310    * ClutterActor:margin-bottom:
6311    *
6312    * The margin (in pixels) from the bottom of the actor.
6313    *
6314    * This property adds a margin to the actor's preferred size; the margin
6315    * will be automatically taken into account when allocating the actor.
6316    *
6317    * Since: 1.10
6318    */
6319   obj_props[PROP_MARGIN_BOTTOM] =
6320     g_param_spec_float ("margin-bottom",
6321                         P_("Margin Bottom"),
6322                         P_("Extra space at the bottom"),
6323                         0.0, G_MAXFLOAT,
6324                         0.0,
6325                         CLUTTER_PARAM_READWRITE);
6326
6327   /**
6328    * ClutterActor:margin-left:
6329    *
6330    * The margin (in pixels) from the left of the actor.
6331    *
6332    * This property adds a margin to the actor's preferred size; the margin
6333    * will be automatically taken into account when allocating the actor.
6334    *
6335    * Since: 1.10
6336    */
6337   obj_props[PROP_MARGIN_LEFT] =
6338     g_param_spec_float ("margin-left",
6339                         P_("Margin Left"),
6340                         P_("Extra space at the left"),
6341                         0.0, G_MAXFLOAT,
6342                         0.0,
6343                         CLUTTER_PARAM_READWRITE);
6344
6345   /**
6346    * ClutterActor:margin-right:
6347    *
6348    * The margin (in pixels) from the right of the actor.
6349    *
6350    * This property adds a margin to the actor's preferred size; the margin
6351    * will be automatically taken into account when allocating the actor.
6352    *
6353    * Since: 1.10
6354    */
6355   obj_props[PROP_MARGIN_RIGHT] =
6356     g_param_spec_float ("margin-right",
6357                         P_("Margin Right"),
6358                         P_("Extra space at the right"),
6359                         0.0, G_MAXFLOAT,
6360                         0.0,
6361                         CLUTTER_PARAM_READWRITE);
6362
6363   /**
6364    * ClutterActor:background-color-set:
6365    *
6366    * Whether the #ClutterActor:background-color property has been set.
6367    *
6368    * Since: 1.10
6369    */
6370   obj_props[PROP_BACKGROUND_COLOR_SET] =
6371     g_param_spec_boolean ("background-color-set",
6372                           P_("Background Color Set"),
6373                           P_("Whether the background color is set"),
6374                           FALSE,
6375                           CLUTTER_PARAM_READABLE);
6376
6377   /**
6378    * ClutterActor:background-color:
6379    *
6380    * Paints a solid fill of the actor's allocation using the specified
6381    * color.
6382    *
6383    * The #ClutterActor:background-color property is animatable.
6384    *
6385    * Since: 1.10
6386    */
6387   obj_props[PROP_BACKGROUND_COLOR] =
6388     clutter_param_spec_color ("background-color",
6389                               P_("Background color"),
6390                               P_("The actor's background color"),
6391                               CLUTTER_COLOR_Transparent,
6392                               G_PARAM_READWRITE |
6393                               G_PARAM_STATIC_STRINGS |
6394                               CLUTTER_PARAM_ANIMATABLE);
6395
6396   /**
6397    * ClutterActor:first-child:
6398    *
6399    * The actor's first child.
6400    *
6401    * Since: 1.10
6402    */
6403   obj_props[PROP_FIRST_CHILD] =
6404     g_param_spec_object ("first-child",
6405                          P_("First Child"),
6406                          P_("The actor's first child"),
6407                          CLUTTER_TYPE_ACTOR,
6408                          CLUTTER_PARAM_READABLE);
6409
6410   /**
6411    * ClutterActor:last-child:
6412    *
6413    * The actor's last child.
6414    *
6415    * Since: 1.10
6416    */
6417   obj_props[PROP_LAST_CHILD] =
6418     g_param_spec_object ("last-child",
6419                          P_("Last Child"),
6420                          P_("The actor's last child"),
6421                          CLUTTER_TYPE_ACTOR,
6422                          CLUTTER_PARAM_READABLE);
6423
6424   /**
6425    * ClutterActor:content:
6426    *
6427    * The #ClutterContent implementation that controls the content
6428    * of the actor.
6429    *
6430    * Since: 1.10
6431    */
6432   obj_props[PROP_CONTENT] =
6433     g_param_spec_object ("content",
6434                          P_("Content"),
6435                          P_("Delegate object for painting the actor's content"),
6436                          CLUTTER_TYPE_CONTENT,
6437                          CLUTTER_PARAM_READWRITE);
6438
6439   /**
6440    * ClutterActor:content-gravity:
6441    *
6442    * The alignment that should be honoured by the #ClutterContent
6443    * set with the #ClutterActor:content property.
6444    *
6445    * Changing the value of this property will change the bounding box of
6446    * the content; you can use the #ClutterActor:content-box property to
6447    * get the position and size of the content within the actor's
6448    * allocation.
6449    *
6450    * This property is meaningful only for #ClutterContent implementations
6451    * that have a preferred size, and if the preferred size is smaller than
6452    * the actor's allocation.
6453    *
6454    * The #ClutterActor:content-gravity property is animatable.
6455    *
6456    * Since: 1.10
6457    */
6458   obj_props[PROP_CONTENT_GRAVITY] =
6459     g_param_spec_enum ("content-gravity",
6460                        P_("Content Gravity"),
6461                        P_("Alignment of the actor's content"),
6462                        CLUTTER_TYPE_CONTENT_GRAVITY,
6463                        CLUTTER_CONTENT_GRAVITY_RESIZE_FILL,
6464                        CLUTTER_PARAM_READWRITE);
6465
6466   /**
6467    * ClutterActor:content-box:
6468    *
6469    * The bounding box for the #ClutterContent used by the actor.
6470    *
6471    * The value of this property is controlled by the #ClutterActor:allocation
6472    * and #ClutterActor:content-gravity properties of #ClutterActor.
6473    *
6474    * The bounding box for the content is guaranteed to never exceed the
6475    * allocation's of the actor.
6476    *
6477    * Since: 1.10
6478    */
6479   obj_props[PROP_CONTENT_BOX] =
6480     g_param_spec_boxed ("content-box",
6481                         P_("Content Box"),
6482                         P_("The bounding box of the actor's content"),
6483                         CLUTTER_TYPE_ACTOR_BOX,
6484                         G_PARAM_READABLE |
6485                         G_PARAM_STATIC_STRINGS |
6486                         CLUTTER_PARAM_ANIMATABLE);
6487
6488   obj_props[PROP_MINIFICATION_FILTER] =
6489     g_param_spec_enum ("minification-filter",
6490                        P_("Minification Filter"),
6491                        P_("The filter used when reducing the size of the content"),
6492                        CLUTTER_TYPE_SCALING_FILTER,
6493                        CLUTTER_SCALING_FILTER_LINEAR,
6494                        CLUTTER_PARAM_READWRITE);
6495
6496   obj_props[PROP_MAGNIFICATION_FILTER] =
6497     g_param_spec_enum ("magnification-filter",
6498                        P_("Magnification Filter"),
6499                        P_("The filter used when increasing the size of the content"),
6500                        CLUTTER_TYPE_SCALING_FILTER,
6501                        CLUTTER_SCALING_FILTER_LINEAR,
6502                        CLUTTER_PARAM_READWRITE);
6503
6504   g_object_class_install_properties (object_class, PROP_LAST, obj_props);
6505
6506   /**
6507    * ClutterActor::destroy:
6508    * @actor: the #ClutterActor which emitted the signal
6509    *
6510    * The ::destroy signal notifies that all references held on the
6511    * actor which emitted it should be released.
6512    *
6513    * The ::destroy signal should be used by all holders of a reference
6514    * on @actor.
6515    *
6516    * This signal might result in the finalization of the #ClutterActor
6517    * if all references are released.
6518    *
6519    * Composite actors and actors implementing the #ClutterContainer
6520    * interface should override the default implementation of the
6521    * class handler of this signal and call clutter_actor_destroy() on
6522    * their children. When overriding the default class handler, it is
6523    * required to chain up to the parent's implementation.
6524    *
6525    * Since: 0.2
6526    */
6527   actor_signals[DESTROY] =
6528     g_signal_new (I_("destroy"),
6529                   G_TYPE_FROM_CLASS (object_class),
6530                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
6531                   G_STRUCT_OFFSET (ClutterActorClass, destroy),
6532                   NULL, NULL,
6533                   _clutter_marshal_VOID__VOID,
6534                   G_TYPE_NONE, 0);
6535   /**
6536    * ClutterActor::show:
6537    * @actor: the object which received the signal
6538    *
6539    * The ::show signal is emitted when an actor is visible and
6540    * rendered on the stage.
6541    *
6542    * Since: 0.2
6543    */
6544   actor_signals[SHOW] =
6545     g_signal_new (I_("show"),
6546                   G_TYPE_FROM_CLASS (object_class),
6547                   G_SIGNAL_RUN_FIRST,
6548                   G_STRUCT_OFFSET (ClutterActorClass, show),
6549                   NULL, NULL,
6550                   _clutter_marshal_VOID__VOID,
6551                   G_TYPE_NONE, 0);
6552   /**
6553    * ClutterActor::hide:
6554    * @actor: the object which received the signal
6555    *
6556    * The ::hide signal is emitted when an actor is no longer rendered
6557    * on the stage.
6558    *
6559    * Since: 0.2
6560    */
6561   actor_signals[HIDE] =
6562     g_signal_new (I_("hide"),
6563                   G_TYPE_FROM_CLASS (object_class),
6564                   G_SIGNAL_RUN_FIRST,
6565                   G_STRUCT_OFFSET (ClutterActorClass, hide),
6566                   NULL, NULL,
6567                   _clutter_marshal_VOID__VOID,
6568                   G_TYPE_NONE, 0);
6569   /**
6570    * ClutterActor::parent-set:
6571    * @actor: the object which received the signal
6572    * @old_parent: (allow-none): the previous parent of the actor, or %NULL
6573    *
6574    * This signal is emitted when the parent of the actor changes.
6575    *
6576    * Since: 0.2
6577    */
6578   actor_signals[PARENT_SET] =
6579     g_signal_new (I_("parent-set"),
6580                   G_TYPE_FROM_CLASS (object_class),
6581                   G_SIGNAL_RUN_LAST,
6582                   G_STRUCT_OFFSET (ClutterActorClass, parent_set),
6583                   NULL, NULL,
6584                   _clutter_marshal_VOID__OBJECT,
6585                   G_TYPE_NONE, 1,
6586                   CLUTTER_TYPE_ACTOR);
6587
6588   /**
6589    * ClutterActor::queue-redraw:
6590    * @actor: the actor we're bubbling the redraw request through
6591    * @origin: the actor which initiated the redraw request
6592    *
6593    * The ::queue_redraw signal is emitted when clutter_actor_queue_redraw()
6594    * is called on @origin.
6595    *
6596    * The default implementation for #ClutterActor chains up to the
6597    * parent actor and queues a redraw on the parent, thus "bubbling"
6598    * the redraw queue up through the actor graph. The default
6599    * implementation for #ClutterStage queues a clutter_stage_ensure_redraw()
6600    * in a main loop idle handler.
6601    *
6602    * Note that the @origin actor may be the stage, or a container; it
6603    * does not have to be a leaf node in the actor graph.
6604    *
6605    * Toolkits embedding a #ClutterStage which require a redraw and
6606    * relayout cycle can stop the emission of this signal using the
6607    * GSignal API, redraw the UI and then call clutter_stage_ensure_redraw()
6608    * themselves, like:
6609    *
6610    * |[
6611    *   static void
6612    *   on_redraw_complete (gpointer data)
6613    *   {
6614    *     ClutterStage *stage = data;
6615    *
6616    *     /&ast; execute the Clutter drawing pipeline &ast;/
6617    *     clutter_stage_ensure_redraw (stage);
6618    *   }
6619    *
6620    *   static void
6621    *   on_stage_queue_redraw (ClutterStage *stage)
6622    *   {
6623    *     /&ast; this prevents the default handler to run &ast;/
6624    *     g_signal_stop_emission_by_name (stage, "queue-redraw");
6625    *
6626    *     /&ast; queue a redraw with the host toolkit and call
6627    *      &ast; a function when the redraw has been completed
6628    *      &ast;/
6629    *     queue_a_redraw (G_CALLBACK (on_redraw_complete), stage);
6630    *   }
6631    * ]|
6632    *
6633    * <note><para>This signal is emitted before the Clutter paint
6634    * pipeline is executed. If you want to know when the pipeline has
6635    * been completed you should connect to the ::paint signal on the
6636    * Stage with g_signal_connect_after().</para></note>
6637    *
6638    * Since: 1.0
6639    */
6640   actor_signals[QUEUE_REDRAW] =
6641     g_signal_new (I_("queue-redraw"),
6642                   G_TYPE_FROM_CLASS (object_class),
6643                   G_SIGNAL_RUN_LAST |
6644                   G_SIGNAL_NO_HOOKS,
6645                   G_STRUCT_OFFSET (ClutterActorClass, queue_redraw),
6646                   NULL, NULL,
6647                   _clutter_marshal_VOID__OBJECT,
6648                   G_TYPE_NONE, 1,
6649                   CLUTTER_TYPE_ACTOR);
6650
6651   /**
6652    * ClutterActor::queue-relayout
6653    * @actor: the actor being queued for relayout
6654    *
6655    * The ::queue_layout signal is emitted when clutter_actor_queue_relayout()
6656    * is called on an actor.
6657    *
6658    * The default implementation for #ClutterActor chains up to the
6659    * parent actor and queues a relayout on the parent, thus "bubbling"
6660    * the relayout queue up through the actor graph.
6661    *
6662    * The main purpose of this signal is to allow relayout to be propagated
6663    * properly in the procense of #ClutterClone actors. Applications will
6664    * not normally need to connect to this signal.
6665    *
6666    * Since: 1.2
6667    */
6668   actor_signals[QUEUE_RELAYOUT] =
6669     g_signal_new (I_("queue-relayout"),
6670                   G_TYPE_FROM_CLASS (object_class),
6671                   G_SIGNAL_RUN_LAST |
6672                   G_SIGNAL_NO_HOOKS,
6673                   G_STRUCT_OFFSET (ClutterActorClass, queue_relayout),
6674                   NULL, NULL,
6675                   _clutter_marshal_VOID__VOID,
6676                   G_TYPE_NONE, 0);
6677
6678   /**
6679    * ClutterActor::event:
6680    * @actor: the actor which received the event
6681    * @event: a #ClutterEvent
6682    *
6683    * The ::event signal is emitted each time an event is received
6684    * by the @actor. This signal will be emitted on every actor,
6685    * following the hierarchy chain, until it reaches the top-level
6686    * container (the #ClutterStage).
6687    *
6688    * Return value: %TRUE if the event has been handled by the actor,
6689    *   or %FALSE to continue the emission.
6690    *
6691    * Since: 0.6
6692    */
6693   actor_signals[EVENT] =
6694     g_signal_new (I_("event"),
6695                   G_TYPE_FROM_CLASS (object_class),
6696                   G_SIGNAL_RUN_LAST,
6697                   G_STRUCT_OFFSET (ClutterActorClass, event),
6698                   _clutter_boolean_handled_accumulator, NULL,
6699                   _clutter_marshal_BOOLEAN__BOXED,
6700                   G_TYPE_BOOLEAN, 1,
6701                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6702   /**
6703    * ClutterActor::button-press-event:
6704    * @actor: the actor which received the event
6705    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6706    *
6707    * The ::button-press-event signal is emitted each time a mouse button
6708    * is pressed on @actor.
6709    *
6710    * Return value: %TRUE if the event has been handled by the actor,
6711    *   or %FALSE to continue the emission.
6712    *
6713    * Since: 0.6
6714    */
6715   actor_signals[BUTTON_PRESS_EVENT] =
6716     g_signal_new (I_("button-press-event"),
6717                   G_TYPE_FROM_CLASS (object_class),
6718                   G_SIGNAL_RUN_LAST,
6719                   G_STRUCT_OFFSET (ClutterActorClass, button_press_event),
6720                   _clutter_boolean_handled_accumulator, NULL,
6721                   _clutter_marshal_BOOLEAN__BOXED,
6722                   G_TYPE_BOOLEAN, 1,
6723                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6724   /**
6725    * ClutterActor::button-release-event:
6726    * @actor: the actor which received the event
6727    * @event: (type ClutterButtonEvent): a #ClutterButtonEvent
6728    *
6729    * The ::button-release-event signal is emitted each time a mouse button
6730    * is released on @actor.
6731    *
6732    * Return value: %TRUE if the event has been handled by the actor,
6733    *   or %FALSE to continue the emission.
6734    *
6735    * Since: 0.6
6736    */
6737   actor_signals[BUTTON_RELEASE_EVENT] =
6738     g_signal_new (I_("button-release-event"),
6739                   G_TYPE_FROM_CLASS (object_class),
6740                   G_SIGNAL_RUN_LAST,
6741                   G_STRUCT_OFFSET (ClutterActorClass, button_release_event),
6742                   _clutter_boolean_handled_accumulator, NULL,
6743                   _clutter_marshal_BOOLEAN__BOXED,
6744                   G_TYPE_BOOLEAN, 1,
6745                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6746   /**
6747    * ClutterActor::scroll-event:
6748    * @actor: the actor which received the event
6749    * @event: (type ClutterScrollEvent): a #ClutterScrollEvent
6750    *
6751    * The ::scroll-event signal is emitted each time the mouse is
6752    * scrolled on @actor
6753    *
6754    * Return value: %TRUE if the event has been handled by the actor,
6755    *   or %FALSE to continue the emission.
6756    *
6757    * Since: 0.6
6758    */
6759   actor_signals[SCROLL_EVENT] =
6760     g_signal_new (I_("scroll-event"),
6761                   G_TYPE_FROM_CLASS (object_class),
6762                   G_SIGNAL_RUN_LAST,
6763                   G_STRUCT_OFFSET (ClutterActorClass, scroll_event),
6764                   _clutter_boolean_handled_accumulator, NULL,
6765                   _clutter_marshal_BOOLEAN__BOXED,
6766                   G_TYPE_BOOLEAN, 1,
6767                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6768   /**
6769    * ClutterActor::key-press-event:
6770    * @actor: the actor which received the event
6771    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6772    *
6773    * The ::key-press-event signal is emitted each time a keyboard button
6774    * is pressed while @actor has key focus (see clutter_stage_set_key_focus()).
6775    *
6776    * Return value: %TRUE if the event has been handled by the actor,
6777    *   or %FALSE to continue the emission.
6778    *
6779    * Since: 0.6
6780    */
6781   actor_signals[KEY_PRESS_EVENT] =
6782     g_signal_new (I_("key-press-event"),
6783                   G_TYPE_FROM_CLASS (object_class),
6784                   G_SIGNAL_RUN_LAST,
6785                   G_STRUCT_OFFSET (ClutterActorClass, key_press_event),
6786                   _clutter_boolean_handled_accumulator, NULL,
6787                   _clutter_marshal_BOOLEAN__BOXED,
6788                   G_TYPE_BOOLEAN, 1,
6789                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6790   /**
6791    * ClutterActor::key-release-event:
6792    * @actor: the actor which received the event
6793    * @event: (type ClutterKeyEvent): a #ClutterKeyEvent
6794    *
6795    * The ::key-release-event signal is emitted each time a keyboard button
6796    * is released while @actor has key focus (see
6797    * clutter_stage_set_key_focus()).
6798    *
6799    * Return value: %TRUE if the event has been handled by the actor,
6800    *   or %FALSE to continue the emission.
6801    *
6802    * Since: 0.6
6803    */
6804   actor_signals[KEY_RELEASE_EVENT] =
6805     g_signal_new (I_("key-release-event"),
6806                   G_TYPE_FROM_CLASS (object_class),
6807                   G_SIGNAL_RUN_LAST,
6808                   G_STRUCT_OFFSET (ClutterActorClass, key_release_event),
6809                   _clutter_boolean_handled_accumulator, NULL,
6810                   _clutter_marshal_BOOLEAN__BOXED,
6811                   G_TYPE_BOOLEAN, 1,
6812                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6813   /**
6814    * ClutterActor::motion-event:
6815    * @actor: the actor which received the event
6816    * @event: (type ClutterMotionEvent): a #ClutterMotionEvent
6817    *
6818    * The ::motion-event signal is emitted each time the mouse pointer is
6819    * moved over @actor.
6820    *
6821    * Return value: %TRUE if the event has been handled by the actor,
6822    *   or %FALSE to continue the emission.
6823    *
6824    * Since: 0.6
6825    */
6826   actor_signals[MOTION_EVENT] =
6827     g_signal_new (I_("motion-event"),
6828                   G_TYPE_FROM_CLASS (object_class),
6829                   G_SIGNAL_RUN_LAST,
6830                   G_STRUCT_OFFSET (ClutterActorClass, motion_event),
6831                   _clutter_boolean_handled_accumulator, NULL,
6832                   _clutter_marshal_BOOLEAN__BOXED,
6833                   G_TYPE_BOOLEAN, 1,
6834                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6835
6836   /**
6837    * ClutterActor::key-focus-in:
6838    * @actor: the actor which now has key focus
6839    *
6840    * The ::key-focus-in signal is emitted when @actor receives key focus.
6841    *
6842    * Since: 0.6
6843    */
6844   actor_signals[KEY_FOCUS_IN] =
6845     g_signal_new (I_("key-focus-in"),
6846                   G_TYPE_FROM_CLASS (object_class),
6847                   G_SIGNAL_RUN_LAST,
6848                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_in),
6849                   NULL, NULL,
6850                   _clutter_marshal_VOID__VOID,
6851                   G_TYPE_NONE, 0);
6852
6853   /**
6854    * ClutterActor::key-focus-out:
6855    * @actor: the actor which now has key focus
6856    *
6857    * The ::key-focus-out signal is emitted when @actor loses key focus.
6858    *
6859    * Since: 0.6
6860    */
6861   actor_signals[KEY_FOCUS_OUT] =
6862     g_signal_new (I_("key-focus-out"),
6863                   G_TYPE_FROM_CLASS (object_class),
6864                   G_SIGNAL_RUN_LAST,
6865                   G_STRUCT_OFFSET (ClutterActorClass, key_focus_out),
6866                   NULL, NULL,
6867                   _clutter_marshal_VOID__VOID,
6868                   G_TYPE_NONE, 0);
6869
6870   /**
6871    * ClutterActor::enter-event:
6872    * @actor: the actor which the pointer has entered.
6873    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6874    *
6875    * The ::enter-event signal is emitted when the pointer enters the @actor
6876    *
6877    * Return value: %TRUE if the event has been handled by the actor,
6878    *   or %FALSE to continue the emission.
6879    *
6880    * Since: 0.6
6881    */
6882   actor_signals[ENTER_EVENT] =
6883     g_signal_new (I_("enter-event"),
6884                   G_TYPE_FROM_CLASS (object_class),
6885                   G_SIGNAL_RUN_LAST,
6886                   G_STRUCT_OFFSET (ClutterActorClass, enter_event),
6887                   _clutter_boolean_handled_accumulator, NULL,
6888                   _clutter_marshal_BOOLEAN__BOXED,
6889                   G_TYPE_BOOLEAN, 1,
6890                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6891
6892   /**
6893    * ClutterActor::leave-event:
6894    * @actor: the actor which the pointer has left
6895    * @event: (type ClutterCrossingEvent): a #ClutterCrossingEvent
6896    *
6897    * The ::leave-event signal is emitted when the pointer leaves the @actor.
6898    *
6899    * Return value: %TRUE if the event has been handled by the actor,
6900    *   or %FALSE to continue the emission.
6901    *
6902    * Since: 0.6
6903    */
6904   actor_signals[LEAVE_EVENT] =
6905     g_signal_new (I_("leave-event"),
6906                   G_TYPE_FROM_CLASS (object_class),
6907                   G_SIGNAL_RUN_LAST,
6908                   G_STRUCT_OFFSET (ClutterActorClass, leave_event),
6909                   _clutter_boolean_handled_accumulator, NULL,
6910                   _clutter_marshal_BOOLEAN__BOXED,
6911                   G_TYPE_BOOLEAN, 1,
6912                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6913
6914   /**
6915    * ClutterActor::captured-event:
6916    * @actor: the actor which received the signal
6917    * @event: a #ClutterEvent
6918    *
6919    * The ::captured-event signal is emitted when an event is captured
6920    * by Clutter. This signal will be emitted starting from the top-level
6921    * container (the #ClutterStage) to the actor which received the event
6922    * going down the hierarchy. This signal can be used to intercept every
6923    * event before the specialized events (like
6924    * ClutterActor::button-press-event or ::key-released-event) are
6925    * emitted.
6926    *
6927    * Return value: %TRUE if the event has been handled by the actor,
6928    *   or %FALSE to continue the emission.
6929    *
6930    * Since: 0.6
6931    */
6932   actor_signals[CAPTURED_EVENT] =
6933     g_signal_new (I_("captured-event"),
6934                   G_TYPE_FROM_CLASS (object_class),
6935                   G_SIGNAL_RUN_LAST,
6936                   G_STRUCT_OFFSET (ClutterActorClass, captured_event),
6937                   _clutter_boolean_handled_accumulator, NULL,
6938                   _clutter_marshal_BOOLEAN__BOXED,
6939                   G_TYPE_BOOLEAN, 1,
6940                   CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
6941
6942   /**
6943    * ClutterActor::paint:
6944    * @actor: the #ClutterActor that received the signal
6945    *
6946    * The ::paint signal is emitted each time an actor is being painted.
6947    *
6948    * Subclasses of #ClutterActor should override the class signal handler
6949    * and paint themselves in that function.
6950    *
6951    * It is possible to connect a handler to the ::paint signal in order
6952    * to set up some custom aspect of a paint.
6953    *
6954    * Since: 0.8
6955    */
6956   actor_signals[PAINT] =
6957     g_signal_new (I_("paint"),
6958                   G_TYPE_FROM_CLASS (object_class),
6959                   G_SIGNAL_RUN_LAST |
6960                   G_SIGNAL_NO_HOOKS,
6961                   G_STRUCT_OFFSET (ClutterActorClass, paint),
6962                   NULL, NULL,
6963                   _clutter_marshal_VOID__VOID,
6964                   G_TYPE_NONE, 0);
6965   /**
6966    * ClutterActor::realize:
6967    * @actor: the #ClutterActor that received the signal
6968    *
6969    * The ::realize signal is emitted each time an actor is being
6970    * realized.
6971    *
6972    * Since: 0.8
6973    */
6974   actor_signals[REALIZE] =
6975     g_signal_new (I_("realize"),
6976                   G_TYPE_FROM_CLASS (object_class),
6977                   G_SIGNAL_RUN_LAST,
6978                   G_STRUCT_OFFSET (ClutterActorClass, realize),
6979                   NULL, NULL,
6980                   _clutter_marshal_VOID__VOID,
6981                   G_TYPE_NONE, 0);
6982   /**
6983    * ClutterActor::unrealize:
6984    * @actor: the #ClutterActor that received the signal
6985    *
6986    * The ::unrealize signal is emitted each time an actor is being
6987    * unrealized.
6988    *
6989    * Since: 0.8
6990    */
6991   actor_signals[UNREALIZE] =
6992     g_signal_new (I_("unrealize"),
6993                   G_TYPE_FROM_CLASS (object_class),
6994                   G_SIGNAL_RUN_LAST,
6995                   G_STRUCT_OFFSET (ClutterActorClass, unrealize),
6996                   NULL, NULL,
6997                   _clutter_marshal_VOID__VOID,
6998                   G_TYPE_NONE, 0);
6999
7000   /**
7001    * ClutterActor::pick:
7002    * @actor: the #ClutterActor that received the signal
7003    * @color: the #ClutterColor to be used when picking
7004    *
7005    * The ::pick signal is emitted each time an actor is being painted
7006    * in "pick mode". The pick mode is used to identify the actor during
7007    * the event handling phase, or by clutter_stage_get_actor_at_pos().
7008    * The actor should paint its shape using the passed @pick_color.
7009    *
7010    * Subclasses of #ClutterActor should override the class signal handler
7011    * and paint themselves in that function.
7012    *
7013    * It is possible to connect a handler to the ::pick signal in order
7014    * to set up some custom aspect of a paint in pick mode.
7015    *
7016    * Since: 1.0
7017    */
7018   actor_signals[PICK] =
7019     g_signal_new (I_("pick"),
7020                   G_TYPE_FROM_CLASS (object_class),
7021                   G_SIGNAL_RUN_LAST,
7022                   G_STRUCT_OFFSET (ClutterActorClass, pick),
7023                   NULL, NULL,
7024                   _clutter_marshal_VOID__BOXED,
7025                   G_TYPE_NONE, 1,
7026                   CLUTTER_TYPE_COLOR | G_SIGNAL_TYPE_STATIC_SCOPE);
7027
7028   /**
7029    * ClutterActor::allocation-changed:
7030    * @actor: the #ClutterActor that emitted the signal
7031    * @box: a #ClutterActorBox with the new allocation
7032    * @flags: #ClutterAllocationFlags for the allocation
7033    *
7034    * The ::allocation-changed signal is emitted when the
7035    * #ClutterActor:allocation property changes. Usually, application
7036    * code should just use the notifications for the :allocation property
7037    * but if you want to track the allocation flags as well, for instance
7038    * to know whether the absolute origin of @actor changed, then you might
7039    * want use this signal instead.
7040    *
7041    * Since: 1.0
7042    */
7043   actor_signals[ALLOCATION_CHANGED] =
7044     g_signal_new (I_("allocation-changed"),
7045                   G_TYPE_FROM_CLASS (object_class),
7046                   G_SIGNAL_RUN_LAST,
7047                   0,
7048                   NULL, NULL,
7049                   _clutter_marshal_VOID__BOXED_FLAGS,
7050                   G_TYPE_NONE, 2,
7051                   CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
7052                   CLUTTER_TYPE_ALLOCATION_FLAGS);
7053
7054   /**
7055    * ClutterActor::transitions-completed:
7056    * @actor: a #ClutterActor
7057    *
7058    * The ::transitions-completed signal is emitted once all transitions
7059    * involving @actor are complete.
7060    *
7061    * Since: 1.10
7062    */
7063   actor_signals[TRANSITIONS_COMPLETED] =
7064     g_signal_new (I_("transitions-completed"),
7065                   G_TYPE_FROM_CLASS (object_class),
7066                   G_SIGNAL_RUN_LAST,
7067                   0,
7068                   NULL, NULL,
7069                   _clutter_marshal_VOID__VOID,
7070                   G_TYPE_NONE, 0);
7071 }
7072
7073 static void
7074 clutter_actor_init (ClutterActor *self)
7075 {
7076   ClutterActorPrivate *priv;
7077
7078   self->priv = priv = CLUTTER_ACTOR_GET_PRIVATE (self);
7079
7080   priv->id = _clutter_context_acquire_id (self);
7081   priv->pick_id = -1;
7082
7083   priv->opacity = 0xff;
7084   priv->show_on_set_parent = TRUE;
7085
7086   priv->needs_width_request = TRUE;
7087   priv->needs_height_request = TRUE;
7088   priv->needs_allocation = TRUE;
7089
7090   priv->cached_width_age = 1;
7091   priv->cached_height_age = 1;
7092
7093   priv->opacity_override = -1;
7094   priv->enable_model_view_transform = TRUE;
7095
7096   /* Initialize an empty paint volume to start with */
7097   _clutter_paint_volume_init_static (&priv->last_paint_volume, NULL);
7098   priv->last_paint_volume_valid = TRUE;
7099
7100   priv->transform_valid = FALSE;
7101
7102   /* the default is to stretch the content, to match the
7103    * current behaviour of basically all actors. also, it's
7104    * the easiest thing to compute.
7105    */
7106   priv->content_gravity = CLUTTER_CONTENT_GRAVITY_RESIZE_FILL;
7107   priv->min_filter = CLUTTER_SCALING_FILTER_LINEAR;
7108   priv->mag_filter = CLUTTER_SCALING_FILTER_LINEAR;
7109 }
7110
7111 /**
7112  * clutter_actor_new:
7113  *
7114  * Creates a new #ClutterActor.
7115  *
7116  * A newly created actor has a floating reference, which will be sunk
7117  * when it is added to another actor.
7118  *
7119  * Return value: (transfer full): the newly created #ClutterActor
7120  *
7121  * Since: 1.10
7122  */
7123 ClutterActor *
7124 clutter_actor_new (void)
7125 {
7126   return g_object_new (CLUTTER_TYPE_ACTOR, NULL);
7127 }
7128
7129 /**
7130  * clutter_actor_destroy:
7131  * @self: a #ClutterActor
7132  *
7133  * Destroys an actor.  When an actor is destroyed, it will break any
7134  * references it holds to other objects.  If the actor is inside a
7135  * container, the actor will be removed.
7136  *
7137  * When you destroy a container, its children will be destroyed as well.
7138  *
7139  * Note: you cannot destroy the #ClutterStage returned by
7140  * clutter_stage_get_default().
7141  */
7142 void
7143 clutter_actor_destroy (ClutterActor *self)
7144 {
7145   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7146
7147   g_object_ref (self);
7148
7149   /* avoid recursion while destroying */
7150   if (!CLUTTER_ACTOR_IN_DESTRUCTION (self))
7151     {
7152       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7153
7154       g_object_run_dispose (G_OBJECT (self));
7155
7156       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_DESTRUCTION);
7157     }
7158
7159   g_object_unref (self);
7160 }
7161
7162 void
7163 _clutter_actor_finish_queue_redraw (ClutterActor *self,
7164                                     ClutterPaintVolume *clip)
7165 {
7166   ClutterActorPrivate *priv = self->priv;
7167   ClutterPaintVolume *pv;
7168   gboolean clipped;
7169
7170   /* Remove queue entry early in the process, otherwise a new
7171      queue_redraw() during signal handling could put back this
7172      object in the stage redraw list (but the entry is freed as
7173      soon as we return from this function, causing a segfault
7174      later)
7175   */
7176   priv->queue_redraw_entry = NULL;
7177
7178   /* If we've been explicitly passed a clip volume then there's
7179    * nothing more to calculate, but otherwise the only thing we know
7180    * is that the change is constrained to the given actor.
7181    *
7182    * The idea is that if we know the paint volume for where the actor
7183    * was last drawn (in eye coordinates) and we also have the paint
7184    * volume for where it will be drawn next (in actor coordinates)
7185    * then if we queue a redraw for both these volumes that will cover
7186    * everything that needs to be redrawn to clear the old view and
7187    * show the latest view of the actor.
7188    *
7189    * Don't clip this redraw if we don't know what position we had for
7190    * the previous redraw since we don't know where to set the clip so
7191    * it will clear the actor as it is currently.
7192    */
7193   if (clip)
7194     {
7195       _clutter_actor_set_queue_redraw_clip (self, clip);
7196       clipped = TRUE;
7197     }
7198   else if (G_LIKELY (priv->last_paint_volume_valid))
7199     {
7200       pv = _clutter_actor_get_paint_volume_mutable (self);
7201       if (pv)
7202         {
7203           ClutterActor *stage = _clutter_actor_get_stage_internal (self);
7204
7205           /* make sure we redraw the actors old position... */
7206           _clutter_actor_set_queue_redraw_clip (stage,
7207                                                 &priv->last_paint_volume);
7208           _clutter_actor_signal_queue_redraw (stage, stage);
7209           _clutter_actor_set_queue_redraw_clip (stage, NULL);
7210
7211           /* XXX: Ideally the redraw signal would take a clip volume
7212            * argument, but that would be an ABI break. Until we can
7213            * break the ABI we pass the argument out-of-band
7214            */
7215
7216           /* setup the clip for the actors new position... */
7217           _clutter_actor_set_queue_redraw_clip (self, pv);
7218           clipped = TRUE;
7219         }
7220       else
7221         clipped = FALSE;
7222     }
7223   else
7224     clipped = FALSE;
7225
7226   _clutter_actor_signal_queue_redraw (self, self);
7227
7228   /* Just in case anyone is manually firing redraw signals without
7229    * using the public queue_redraw() API we are careful to ensure that
7230    * our out-of-band clip member is cleared before returning...
7231    *
7232    * Note: A NULL clip denotes a full-stage, un-clipped redraw
7233    */
7234   if (G_LIKELY (clipped))
7235     _clutter_actor_set_queue_redraw_clip (self, NULL);
7236 }
7237
7238 static void
7239 _clutter_actor_get_allocation_clip (ClutterActor *self,
7240                                     ClutterActorBox *clip)
7241 {
7242   ClutterActorBox allocation;
7243
7244   /* XXX: we don't care if we get an out of date allocation here
7245    * because clutter_actor_queue_redraw_with_clip knows to ignore
7246    * the clip if the actor's allocation is invalid.
7247    *
7248    * This is noted because clutter_actor_get_allocation_box does some
7249    * unnecessary work to support buggy code with a comment suggesting
7250    * that it could be changed later which would be good for this use
7251    * case!
7252    */
7253   clutter_actor_get_allocation_box (self, &allocation);
7254
7255   /* NB: clutter_actor_queue_redraw_with_clip expects a box in the
7256    * actor's own coordinate space but the allocation is in parent
7257    * coordinates */
7258   clip->x1 = 0;
7259   clip->y1 = 0;
7260   clip->x2 = allocation.x2 - allocation.x1;
7261   clip->y2 = allocation.y2 - allocation.y1;
7262 }
7263
7264 void
7265 _clutter_actor_queue_redraw_full (ClutterActor       *self,
7266                                   ClutterRedrawFlags  flags,
7267                                   ClutterPaintVolume *volume,
7268                                   ClutterEffect      *effect)
7269 {
7270   ClutterActorPrivate *priv = self->priv;
7271   ClutterPaintVolume allocation_pv;
7272   ClutterPaintVolume *pv;
7273   gboolean should_free_pv;
7274   ClutterActor *stage;
7275
7276   /* Here's an outline of the actor queue redraw mechanism:
7277    *
7278    * The process starts in one of the following two functions which
7279    * are wrappers for this function:
7280    * clutter_actor_queue_redraw
7281    * _clutter_actor_queue_redraw_with_clip
7282    *
7283    * additionally, an effect can queue a redraw by wrapping this
7284    * function in clutter_effect_queue_rerun
7285    *
7286    * This functions queues an entry in a list associated with the
7287    * stage which is a list of actors that queued a redraw while
7288    * updating the timelines, performing layouting and processing other
7289    * mainloop sources before the next paint starts.
7290    *
7291    * We aim to minimize the processing done at this point because
7292    * there is a good chance other events will happen while updating
7293    * the scenegraph that would invalidate any expensive work we might
7294    * otherwise try to do here. For example we don't try and resolve
7295    * the screen space bounding box of an actor at this stage so as to
7296    * minimize how much of the screen redraw because it's possible
7297    * something else will happen which will force a full redraw anyway.
7298    *
7299    * When all updates are complete and we come to paint the stage then
7300    * we iterate this list and actually emit the "queue-redraw" signals
7301    * for each of the listed actors which will bubble up to the stage
7302    * for each actor and at that point we will transform the actors
7303    * paint volume into screen coordinates to determine the clip region
7304    * for what needs to be redrawn in the next paint.
7305    *
7306    * Besides minimizing redundant work another reason for this
7307    * deferred design is that it's more likely we will be able to
7308    * determine the paint volume of an actor once we've finished
7309    * updating the scenegraph because its allocation should be up to
7310    * date. NB: If we can't determine an actors paint volume then we
7311    * can't automatically queue a clipped redraw which can make a big
7312    * difference to performance.
7313    *
7314    * So the control flow goes like this:
7315    * One of clutter_actor_queue_redraw,
7316    *        _clutter_actor_queue_redraw_with_clip
7317    *     or clutter_effect_queue_rerun
7318    *
7319    * then control moves to:
7320    *   _clutter_stage_queue_actor_redraw
7321    *
7322    * later during _clutter_stage_do_update, once relayouting is done
7323    * and the scenegraph has been updated we will call:
7324    * _clutter_stage_finish_queue_redraws
7325    *
7326    * _clutter_stage_finish_queue_redraws will call
7327    * _clutter_actor_finish_queue_redraw for each listed actor.
7328    * Note: actors *are* allowed to queue further redraws during this
7329    * process (considering clone actors or texture_new_from_actor which
7330    * respond to their source queueing a redraw by queuing a redraw
7331    * themselves). We repeat the process until the list is empty.
7332    *
7333    * This will result in the "queue-redraw" signal being fired for
7334    * each actor which will pass control to the default signal handler:
7335    * clutter_actor_real_queue_redraw
7336    *
7337    * This will bubble up to the stages handler:
7338    * clutter_stage_real_queue_redraw
7339    *
7340    * clutter_stage_real_queue_redraw will transform the actors paint
7341    * volume into screen space and add it as a clip region for the next
7342    * paint.
7343    */
7344
7345   /* ignore queueing a redraw for actors being destroyed */
7346   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7347     return;
7348
7349   stage = _clutter_actor_get_stage_internal (self);
7350
7351   /* Ignore queueing a redraw for actors not descended from a stage */
7352   if (stage == NULL)
7353     return;
7354
7355   /* ignore queueing a redraw on stages that are being destroyed */
7356   if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
7357     return;
7358
7359   if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
7360     {
7361       ClutterActorBox allocation_clip;
7362       ClutterVertex origin;
7363
7364       /* If the actor doesn't have a valid allocation then we will
7365        * queue a full stage redraw. */
7366       if (priv->needs_allocation)
7367         {
7368           /* NB: NULL denotes an undefined clip which will result in a
7369            * full redraw... */
7370           _clutter_actor_set_queue_redraw_clip (self, NULL);
7371           _clutter_actor_signal_queue_redraw (self, self);
7372           return;
7373         }
7374
7375       _clutter_paint_volume_init_static (&allocation_pv, self);
7376       pv = &allocation_pv;
7377
7378       _clutter_actor_get_allocation_clip (self, &allocation_clip);
7379
7380       origin.x = allocation_clip.x1;
7381       origin.y = allocation_clip.y1;
7382       origin.z = 0;
7383       clutter_paint_volume_set_origin (pv, &origin);
7384       clutter_paint_volume_set_width (pv,
7385                                       allocation_clip.x2 - allocation_clip.x1);
7386       clutter_paint_volume_set_height (pv,
7387                                        allocation_clip.y2 -
7388                                        allocation_clip.y1);
7389       should_free_pv = TRUE;
7390     }
7391   else
7392     {
7393       pv = volume;
7394       should_free_pv = FALSE;
7395     }
7396
7397   self->priv->queue_redraw_entry =
7398     _clutter_stage_queue_actor_redraw (CLUTTER_STAGE (stage),
7399                                        priv->queue_redraw_entry,
7400                                        self,
7401                                        pv);
7402
7403   if (should_free_pv)
7404     clutter_paint_volume_free (pv);
7405
7406   /* If this is the first redraw queued then we can directly use the
7407      effect parameter */
7408   if (!priv->is_dirty)
7409     priv->effect_to_redraw = effect;
7410   /* Otherwise we need to merge it with the existing effect parameter */
7411   else if (effect != NULL)
7412     {
7413       /* If there's already an effect then we need to use whichever is
7414          later in the chain of actors. Otherwise a full redraw has
7415          already been queued on the actor so we need to ignore the
7416          effect parameter */
7417       if (priv->effect_to_redraw != NULL)
7418         {
7419           if (priv->effects == NULL)
7420             g_warning ("Redraw queued with an effect that is "
7421                        "not applied to the actor");
7422           else
7423             {
7424               const GList *l;
7425
7426               for (l = _clutter_meta_group_peek_metas (priv->effects);
7427                    l != NULL;
7428                    l = l->next)
7429                 {
7430                   if (l->data == priv->effect_to_redraw ||
7431                       l->data == effect)
7432                     priv->effect_to_redraw = l->data;
7433                 }
7434             }
7435         }
7436     }
7437   else
7438     {
7439       /* If no effect is specified then we need to redraw the whole
7440          actor */
7441       priv->effect_to_redraw = NULL;
7442     }
7443
7444   priv->is_dirty = TRUE;
7445 }
7446
7447 /**
7448  * clutter_actor_queue_redraw:
7449  * @self: A #ClutterActor
7450  *
7451  * Queues up a redraw of an actor and any children. The redraw occurs
7452  * once the main loop becomes idle (after the current batch of events
7453  * has been processed, roughly).
7454  *
7455  * Applications rarely need to call this, as redraws are handled
7456  * automatically by modification functions.
7457  *
7458  * This function will not do anything if @self is not visible, or
7459  * if the actor is inside an invisible part of the scenegraph.
7460  *
7461  * Also be aware that painting is a NOP for actors with an opacity of
7462  * 0
7463  *
7464  * When you are implementing a custom actor you must queue a redraw
7465  * whenever some private state changes that will affect painting or
7466  * picking of your actor.
7467  */
7468 void
7469 clutter_actor_queue_redraw (ClutterActor *self)
7470 {
7471   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7472
7473   _clutter_actor_queue_redraw_full (self,
7474                                     0, /* flags */
7475                                     NULL, /* clip volume */
7476                                     NULL /* effect */);
7477 }
7478
7479 /*< private >
7480  * _clutter_actor_queue_redraw_with_clip:
7481  * @self: A #ClutterActor
7482  * @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
7483  *   this queue redraw.
7484  * @volume: A #ClutterPaintVolume describing the bounds of what needs to be
7485  *   redrawn or %NULL if you are just using a @flag to state your
7486  *   desired clipping.
7487  *
7488  * Queues up a clipped redraw of an actor and any children. The redraw
7489  * occurs once the main loop becomes idle (after the current batch of
7490  * events has been processed, roughly).
7491  *
7492  * If no flags are given the clip volume is defined by @volume
7493  * specified in actor coordinates and tells Clutter that only content
7494  * within this volume has been changed so Clutter can optionally
7495  * optimize the redraw.
7496  *
7497  * If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
7498  * should be %NULL and this tells Clutter to use the actor's current
7499  * allocation as a clip box. This flag can only be used for 2D actors,
7500  * because any actor with depth may be projected outside its
7501  * allocation.
7502  *
7503  * Applications rarely need to call this, as redraws are handled
7504  * automatically by modification functions.
7505  *
7506  * This function will not do anything if @self is not visible, or if
7507  * the actor is inside an invisible part of the scenegraph.
7508  *
7509  * Also be aware that painting is a NOP for actors with an opacity of
7510  * 0
7511  *
7512  * When you are implementing a custom actor you must queue a redraw
7513  * whenever some private state changes that will affect painting or
7514  * picking of your actor.
7515  */
7516 void
7517 _clutter_actor_queue_redraw_with_clip (ClutterActor       *self,
7518                                        ClutterRedrawFlags  flags,
7519                                        ClutterPaintVolume *volume)
7520 {
7521   _clutter_actor_queue_redraw_full (self,
7522                                     flags, /* flags */
7523                                     volume, /* clip volume */
7524                                     NULL /* effect */);
7525 }
7526
7527 static void
7528 _clutter_actor_queue_only_relayout (ClutterActor *self)
7529 {
7530   ClutterActorPrivate *priv = self->priv;
7531
7532   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
7533     return;
7534
7535   if (priv->needs_width_request &&
7536       priv->needs_height_request &&
7537       priv->needs_allocation)
7538     return; /* save some cpu cycles */
7539
7540 #if CLUTTER_ENABLE_DEBUG
7541   if (!CLUTTER_ACTOR_IS_TOPLEVEL (self) && CLUTTER_ACTOR_IN_RELAYOUT (self))
7542     {
7543       g_warning ("The actor '%s' is currently inside an allocation "
7544                  "cycle; calling clutter_actor_queue_relayout() is "
7545                  "not recommended",
7546                  _clutter_actor_get_debug_name (self));
7547     }
7548 #endif /* CLUTTER_ENABLE_DEBUG */
7549
7550   g_signal_emit (self, actor_signals[QUEUE_RELAYOUT], 0);
7551 }
7552
7553 /**
7554  * clutter_actor_queue_redraw_with_clip:
7555  * @self: a #ClutterActor
7556  * @clip: (allow-none): a rectangular clip region, or %NULL
7557  *
7558  * Queues a redraw on @self limited to a specific, actor-relative
7559  * rectangular area.
7560  *
7561  * If @clip is %NULL this function is equivalent to
7562  * clutter_actor_queue_redraw().
7563  *
7564  * Since: 1.10
7565  */
7566 void
7567 clutter_actor_queue_redraw_with_clip (ClutterActor                *self,
7568                                       const cairo_rectangle_int_t *clip)
7569 {
7570   ClutterPaintVolume volume;
7571   ClutterVertex origin;
7572
7573   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7574
7575   if (clip == NULL)
7576     {
7577       clutter_actor_queue_redraw (self);
7578       return;
7579     }
7580
7581   _clutter_paint_volume_init_static (&volume, self);
7582
7583   origin.x = clip->x;
7584   origin.y = clip->y;
7585   origin.z = 0.0f;
7586
7587   clutter_paint_volume_set_origin (&volume, &origin);
7588   clutter_paint_volume_set_width (&volume, clip->width);
7589   clutter_paint_volume_set_height (&volume, clip->height);
7590
7591   _clutter_actor_queue_redraw_full (self, 0, &volume, NULL);
7592
7593   clutter_paint_volume_free (&volume);
7594 }
7595
7596 /**
7597  * clutter_actor_queue_relayout:
7598  * @self: A #ClutterActor
7599  *
7600  * Indicates that the actor's size request or other layout-affecting
7601  * properties may have changed. This function is used inside #ClutterActor
7602  * subclass implementations, not by applications directly.
7603  *
7604  * Queueing a new layout automatically queues a redraw as well.
7605  *
7606  * Since: 0.8
7607  */
7608 void
7609 clutter_actor_queue_relayout (ClutterActor *self)
7610 {
7611   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7612
7613   _clutter_actor_queue_only_relayout (self);
7614   clutter_actor_queue_redraw (self);
7615 }
7616
7617 /**
7618  * clutter_actor_get_preferred_size:
7619  * @self: a #ClutterActor
7620  * @min_width_p: (out) (allow-none): return location for the minimum
7621  *   width, or %NULL
7622  * @min_height_p: (out) (allow-none): return location for the minimum
7623  *   height, or %NULL
7624  * @natural_width_p: (out) (allow-none): return location for the natural
7625  *   width, or %NULL
7626  * @natural_height_p: (out) (allow-none): return location for the natural
7627  *   height, or %NULL
7628  *
7629  * Computes the preferred minimum and natural size of an actor, taking into
7630  * account the actor's geometry management (either height-for-width
7631  * or width-for-height).
7632  *
7633  * The width and height used to compute the preferred height and preferred
7634  * width are the actor's natural ones.
7635  *
7636  * If you need to control the height for the preferred width, or the width for
7637  * the preferred height, you should use clutter_actor_get_preferred_width()
7638  * and clutter_actor_get_preferred_height(), and check the actor's preferred
7639  * geometry management using the #ClutterActor:request-mode property.
7640  *
7641  * Since: 0.8
7642  */
7643 void
7644 clutter_actor_get_preferred_size (ClutterActor *self,
7645                                   gfloat       *min_width_p,
7646                                   gfloat       *min_height_p,
7647                                   gfloat       *natural_width_p,
7648                                   gfloat       *natural_height_p)
7649 {
7650   ClutterActorPrivate *priv;
7651   gfloat min_width, min_height;
7652   gfloat natural_width, natural_height;
7653
7654   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7655
7656   priv = self->priv;
7657
7658   min_width = min_height = 0;
7659   natural_width = natural_height = 0;
7660
7661   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
7662     {
7663       CLUTTER_NOTE (LAYOUT, "Preferred size (height-for-width)");
7664       clutter_actor_get_preferred_width (self, -1,
7665                                          &min_width,
7666                                          &natural_width);
7667       clutter_actor_get_preferred_height (self, natural_width,
7668                                           &min_height,
7669                                           &natural_height);
7670     }
7671   else
7672     {
7673       CLUTTER_NOTE (LAYOUT, "Preferred size (width-for-height)");
7674       clutter_actor_get_preferred_height (self, -1,
7675                                           &min_height,
7676                                           &natural_height);
7677       clutter_actor_get_preferred_width (self, natural_height,
7678                                          &min_width,
7679                                          &natural_width);
7680     }
7681
7682   if (min_width_p)
7683     *min_width_p = min_width;
7684
7685   if (min_height_p)
7686     *min_height_p = min_height;
7687
7688   if (natural_width_p)
7689     *natural_width_p = natural_width;
7690
7691   if (natural_height_p)
7692     *natural_height_p = natural_height;
7693 }
7694
7695 /*< private >
7696  * effective_align:
7697  * @align: a #ClutterActorAlign
7698  * @direction: a #ClutterTextDirection
7699  *
7700  * Retrieves the correct alignment depending on the text direction
7701  *
7702  * Return value: the effective alignment
7703  */
7704 static ClutterActorAlign
7705 effective_align (ClutterActorAlign    align,
7706                  ClutterTextDirection direction)
7707 {
7708   ClutterActorAlign res;
7709
7710   switch (align)
7711     {
7712     case CLUTTER_ACTOR_ALIGN_START:
7713       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7714           ? CLUTTER_ACTOR_ALIGN_END
7715           : CLUTTER_ACTOR_ALIGN_START;
7716       break;
7717
7718     case CLUTTER_ACTOR_ALIGN_END:
7719       res = (direction == CLUTTER_TEXT_DIRECTION_RTL)
7720           ? CLUTTER_ACTOR_ALIGN_START
7721           : CLUTTER_ACTOR_ALIGN_END;
7722       break;
7723
7724     default:
7725       res = align;
7726       break;
7727     }
7728
7729   return res;
7730 }
7731
7732 static inline void
7733 adjust_for_margin (float  margin_start,
7734                    float  margin_end,
7735                    float *minimum_size,
7736                    float *natural_size,
7737                    float *allocated_start,
7738                    float *allocated_end)
7739 {
7740   *minimum_size -= (margin_start + margin_end);
7741   *natural_size -= (margin_start + margin_end);
7742   *allocated_start += margin_start;
7743   *allocated_end -= margin_end;
7744 }
7745
7746 static inline void
7747 adjust_for_alignment (ClutterActorAlign  alignment,
7748                       float              natural_size,
7749                       float             *allocated_start,
7750                       float             *allocated_end)
7751 {
7752   float allocated_size = *allocated_end - *allocated_start;
7753
7754   switch (alignment)
7755     {
7756     case CLUTTER_ACTOR_ALIGN_FILL:
7757       /* do nothing */
7758       break;
7759
7760     case CLUTTER_ACTOR_ALIGN_START:
7761       /* keep start */
7762       *allocated_end = *allocated_start + MIN (natural_size, allocated_size);
7763       break;
7764
7765     case CLUTTER_ACTOR_ALIGN_END:
7766       if (allocated_size > natural_size)
7767         {
7768           *allocated_start += (allocated_size - natural_size);
7769           *allocated_end = *allocated_start + natural_size;
7770         }
7771       break;
7772
7773     case CLUTTER_ACTOR_ALIGN_CENTER:
7774       if (allocated_size > natural_size)
7775         {
7776           *allocated_start += ceilf ((allocated_size - natural_size) / 2);
7777           *allocated_end = *allocated_start + MIN (allocated_size, natural_size);
7778         }
7779       break;
7780     }
7781 }
7782
7783 /*< private >
7784  * clutter_actor_adjust_width:
7785  * @self: a #ClutterActor
7786  * @minimum_width: (inout): the actor's preferred minimum width, which
7787  *   will be adjusted depending on the margin
7788  * @natural_width: (inout): the actor's preferred natural width, which
7789  *   will be adjusted depending on the margin
7790  * @adjusted_x1: (out): the adjusted x1 for the actor's bounding box
7791  * @adjusted_x2: (out): the adjusted x2 for the actor's bounding box
7792  *
7793  * Adjusts the preferred and allocated position and size of an actor,
7794  * depending on the margin and alignment properties.
7795  */
7796 static void
7797 clutter_actor_adjust_width (ClutterActor *self,
7798                             gfloat       *minimum_width,
7799                             gfloat       *natural_width,
7800                             gfloat       *adjusted_x1,
7801                             gfloat       *adjusted_x2)
7802 {
7803   ClutterTextDirection text_dir;
7804   const ClutterLayoutInfo *info;
7805
7806   info = _clutter_actor_get_layout_info_or_defaults (self);
7807   text_dir = clutter_actor_get_text_direction (self);
7808
7809   CLUTTER_NOTE (LAYOUT, "Adjusting allocated X and width");
7810
7811   /* this will tweak natural_width to remove the margin, so that
7812    * adjust_for_alignment() will use the correct size
7813    */
7814   adjust_for_margin (info->margin.left, info->margin.right,
7815                      minimum_width, natural_width,
7816                      adjusted_x1, adjusted_x2);
7817
7818   adjust_for_alignment (effective_align (info->x_align, text_dir),
7819                         *natural_width,
7820                         adjusted_x1, adjusted_x2);
7821 }
7822
7823 /*< private >
7824  * clutter_actor_adjust_height:
7825  * @self: a #ClutterActor
7826  * @minimum_height: (inout): the actor's preferred minimum height, which
7827  *   will be adjusted depending on the margin
7828  * @natural_height: (inout): the actor's preferred natural height, which
7829  *   will be adjusted depending on the margin
7830  * @adjusted_y1: (out): the adjusted y1 for the actor's bounding box
7831  * @adjusted_y2: (out): the adjusted y2 for the actor's bounding box
7832  *
7833  * Adjusts the preferred and allocated position and size of an actor,
7834  * depending on the margin and alignment properties.
7835  */
7836 static void
7837 clutter_actor_adjust_height (ClutterActor *self,
7838                              gfloat       *minimum_height,
7839                              gfloat       *natural_height,
7840                              gfloat       *adjusted_y1,
7841                              gfloat       *adjusted_y2)
7842 {
7843   const ClutterLayoutInfo *info;
7844
7845   info = _clutter_actor_get_layout_info_or_defaults (self);
7846
7847   CLUTTER_NOTE (LAYOUT, "Adjusting allocated Y and height");
7848
7849   /* this will tweak natural_height to remove the margin, so that
7850    * adjust_for_alignment() will use the correct size
7851    */
7852   adjust_for_margin (info->margin.top, info->margin.bottom,
7853                      minimum_height, natural_height,
7854                      adjusted_y1,
7855                      adjusted_y2);
7856
7857   /* we don't use effective_align() here, because text direction
7858    * only affects the horizontal axis
7859    */
7860   adjust_for_alignment (info->y_align,
7861                         *natural_height,
7862                         adjusted_y1,
7863                         adjusted_y2);
7864
7865 }
7866
7867 /* looks for a cached size request for this for_size. If not
7868  * found, returns the oldest entry so it can be overwritten */
7869 static gboolean
7870 _clutter_actor_get_cached_size_request (gfloat         for_size,
7871                                         SizeRequest   *cached_size_requests,
7872                                         SizeRequest  **result)
7873 {
7874   guint i;
7875
7876   *result = &cached_size_requests[0];
7877
7878   for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
7879     {
7880       SizeRequest *sr;
7881
7882       sr = &cached_size_requests[i];
7883
7884       if (sr->age > 0 &&
7885           sr->for_size == for_size)
7886         {
7887           CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
7888           *result = sr;
7889           return TRUE;
7890         }
7891       else if (sr->age < (*result)->age)
7892         {
7893           *result = sr;
7894         }
7895     }
7896
7897   CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
7898
7899   return FALSE;
7900 }
7901
7902 /**
7903  * clutter_actor_get_preferred_width:
7904  * @self: A #ClutterActor
7905  * @for_height: available height when computing the preferred width,
7906  *   or a negative value to indicate that no height is defined
7907  * @min_width_p: (out) (allow-none): return location for minimum width,
7908  *   or %NULL
7909  * @natural_width_p: (out) (allow-none): return location for the natural
7910  *   width, or %NULL
7911  *
7912  * Computes the requested minimum and natural widths for an actor,
7913  * optionally depending on the specified height, or if they are
7914  * already computed, returns the cached values.
7915  *
7916  * An actor may not get its request - depending on the layout
7917  * manager that's in effect.
7918  *
7919  * A request should not incorporate the actor's scale or anchor point;
7920  * those transformations do not affect layout, only rendering.
7921  *
7922  * Since: 0.8
7923  */
7924 void
7925 clutter_actor_get_preferred_width (ClutterActor *self,
7926                                    gfloat        for_height,
7927                                    gfloat       *min_width_p,
7928                                    gfloat       *natural_width_p)
7929 {
7930   float request_min_width, request_natural_width;
7931   SizeRequest *cached_size_request;
7932   const ClutterLayoutInfo *info;
7933   ClutterActorPrivate *priv;
7934   gboolean found_in_cache;
7935
7936   g_return_if_fail (CLUTTER_IS_ACTOR (self));
7937
7938   priv = self->priv;
7939
7940   info = _clutter_actor_get_layout_info_or_defaults (self);
7941
7942   /* we shortcircuit the case of a fixed size set using set_width() */
7943   if (priv->min_width_set && priv->natural_width_set)
7944     {
7945       if (min_width_p != NULL)
7946         *min_width_p = info->min_width + (info->margin.left + info->margin.right);
7947
7948       if (natural_width_p != NULL)
7949         *natural_width_p = info->natural_width + (info->margin.left + info->margin.right);
7950
7951       return;
7952     }
7953
7954   /* the remaining cases are:
7955    *
7956    *   - either min_width or natural_width have been set
7957    *   - neither min_width or natural_width have been set
7958    *
7959    * in both cases, we go through the cache (and through the actor in case
7960    * of cache misses) and determine the authoritative value depending on
7961    * the *_set flags.
7962    */
7963
7964   if (!priv->needs_width_request)
7965     {
7966       found_in_cache =
7967         _clutter_actor_get_cached_size_request (for_height,
7968                                                 priv->width_requests,
7969                                                 &cached_size_request);
7970     }
7971   else
7972     {
7973       /* if the actor needs a width request we use the first slot */
7974       found_in_cache = FALSE;
7975       cached_size_request = &priv->width_requests[0];
7976     }
7977
7978   if (!found_in_cache)
7979     {
7980       gfloat minimum_width, natural_width;
7981       ClutterActorClass *klass;
7982
7983       minimum_width = natural_width = 0;
7984
7985       /* adjust for the margin */
7986       if (for_height >= 0)
7987         {
7988           for_height -= (info->margin.top + info->margin.bottom);
7989           if (for_height < 0)
7990             for_height = 0;
7991         }
7992
7993       CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_height);
7994
7995       klass = CLUTTER_ACTOR_GET_CLASS (self);
7996       klass->get_preferred_width (self, for_height,
7997                                   &minimum_width,
7998                                   &natural_width);
7999
8000       /* adjust for the margin */
8001       minimum_width += (info->margin.left + info->margin.right);
8002       natural_width += (info->margin.left + info->margin.right);
8003
8004       /* Due to accumulated float errors, it's better not to warn
8005        * on this, but just fix it.
8006        */
8007       if (natural_width < minimum_width)
8008         natural_width = minimum_width;
8009
8010       cached_size_request->min_size = minimum_width;
8011       cached_size_request->natural_size = natural_width;
8012       cached_size_request->for_size = for_height;
8013       cached_size_request->age = priv->cached_width_age;
8014
8015       priv->cached_width_age += 1;
8016       priv->needs_width_request = FALSE;
8017     }
8018
8019   if (!priv->min_width_set)
8020     request_min_width = cached_size_request->min_size;
8021   else
8022     request_min_width = info->min_width;
8023
8024   if (!priv->natural_width_set)
8025     request_natural_width = cached_size_request->natural_size;
8026   else
8027     request_natural_width = info->natural_width;
8028
8029   if (min_width_p)
8030     *min_width_p = request_min_width;
8031
8032   if (natural_width_p)
8033     *natural_width_p = request_natural_width;
8034 }
8035
8036 /**
8037  * clutter_actor_get_preferred_height:
8038  * @self: A #ClutterActor
8039  * @for_width: available width to assume in computing desired height,
8040  *   or a negative value to indicate that no width is defined
8041  * @min_height_p: (out) (allow-none): return location for minimum height,
8042  *   or %NULL
8043  * @natural_height_p: (out) (allow-none): return location for natural
8044  *   height, or %NULL
8045  *
8046  * Computes the requested minimum and natural heights for an actor,
8047  * or if they are already computed, returns the cached values.
8048  *
8049  * An actor may not get its request - depending on the layout
8050  * manager that's in effect.
8051  *
8052  * A request should not incorporate the actor's scale or anchor point;
8053  * those transformations do not affect layout, only rendering.
8054  *
8055  * Since: 0.8
8056  */
8057 void
8058 clutter_actor_get_preferred_height (ClutterActor *self,
8059                                     gfloat        for_width,
8060                                     gfloat       *min_height_p,
8061                                     gfloat       *natural_height_p)
8062 {
8063   float request_min_height, request_natural_height;
8064   SizeRequest *cached_size_request;
8065   const ClutterLayoutInfo *info;
8066   ClutterActorPrivate *priv;
8067   gboolean found_in_cache;
8068
8069   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8070
8071   priv = self->priv;
8072
8073   info = _clutter_actor_get_layout_info_or_defaults (self);
8074
8075   /* we shortcircuit the case of a fixed size set using set_height() */
8076   if (priv->min_height_set && priv->natural_height_set)
8077     {
8078       if (min_height_p != NULL)
8079         *min_height_p = info->min_height + (info->margin.top + info->margin.bottom);
8080
8081       if (natural_height_p != NULL)
8082         *natural_height_p = info->natural_height + (info->margin.top + info->margin.bottom);
8083
8084       return;
8085     }
8086
8087   /* the remaining cases are:
8088    *
8089    *   - either min_height or natural_height have been set
8090    *   - neither min_height or natural_height have been set
8091    *
8092    * in both cases, we go through the cache (and through the actor in case
8093    * of cache misses) and determine the authoritative value depending on
8094    * the *_set flags.
8095    */
8096
8097   if (!priv->needs_height_request)
8098     {
8099       found_in_cache =
8100         _clutter_actor_get_cached_size_request (for_width,
8101                                                 priv->height_requests,
8102                                                 &cached_size_request);
8103     }
8104   else
8105     {
8106       found_in_cache = FALSE;
8107       cached_size_request = &priv->height_requests[0];
8108     }
8109
8110   if (!found_in_cache)
8111     {
8112       gfloat minimum_height, natural_height;
8113       ClutterActorClass *klass;
8114
8115       minimum_height = natural_height = 0;
8116
8117       CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
8118
8119       /* adjust for margin */
8120       if (for_width >= 0)
8121         {
8122           for_width -= (info->margin.left + info->margin.right);
8123           if (for_width < 0)
8124             for_width = 0;
8125         }
8126
8127       klass = CLUTTER_ACTOR_GET_CLASS (self);
8128       klass->get_preferred_height (self, for_width,
8129                                    &minimum_height,
8130                                    &natural_height);
8131
8132       /* adjust for margin */
8133       minimum_height += (info->margin.top + info->margin.bottom);
8134       natural_height += (info->margin.top + info->margin.bottom);
8135
8136       /* Due to accumulated float errors, it's better not to warn
8137        * on this, but just fix it.
8138        */
8139       if (natural_height < minimum_height)
8140         natural_height = minimum_height;
8141
8142       cached_size_request->min_size = minimum_height;
8143       cached_size_request->natural_size = natural_height;
8144       cached_size_request->for_size = for_width;
8145       cached_size_request->age = priv->cached_height_age;
8146
8147       priv->cached_height_age += 1;
8148       priv->needs_height_request = FALSE;
8149     }
8150
8151   if (!priv->min_height_set)
8152     request_min_height = cached_size_request->min_size;
8153   else
8154     request_min_height = info->min_height;
8155
8156   if (!priv->natural_height_set)
8157     request_natural_height = cached_size_request->natural_size;
8158   else
8159     request_natural_height = info->natural_height;
8160
8161   if (min_height_p)
8162     *min_height_p = request_min_height;
8163
8164   if (natural_height_p)
8165     *natural_height_p = request_natural_height;
8166 }
8167
8168 /**
8169  * clutter_actor_get_allocation_box:
8170  * @self: A #ClutterActor
8171  * @box: (out): the function fills this in with the actor's allocation
8172  *
8173  * Gets the layout box an actor has been assigned. The allocation can
8174  * only be assumed valid inside a paint() method; anywhere else, it
8175  * may be out-of-date.
8176  *
8177  * An allocation does not incorporate the actor's scale or anchor point;
8178  * those transformations do not affect layout, only rendering.
8179  *
8180  * <note>Do not call any of the clutter_actor_get_allocation_*() family
8181  * of functions inside the implementation of the get_preferred_width()
8182  * or get_preferred_height() virtual functions.</note>
8183  *
8184  * Since: 0.8
8185  */
8186 void
8187 clutter_actor_get_allocation_box (ClutterActor    *self,
8188                                   ClutterActorBox *box)
8189 {
8190   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8191
8192   /* XXX - if needs_allocation=TRUE, we can either 1) g_return_if_fail,
8193    * which limits calling get_allocation to inside paint() basically; or
8194    * we can 2) force a layout, which could be expensive if someone calls
8195    * get_allocation somewhere silly; or we can 3) just return the latest
8196    * value, allowing it to be out-of-date, and assume people know what
8197    * they are doing.
8198    *
8199    * The least-surprises approach that keeps existing code working is
8200    * likely to be 2). People can end up doing some inefficient things,
8201    * though, and in general code that requires 2) is probably broken.
8202    */
8203
8204   /* this implements 2) */
8205   if (G_UNLIKELY (self->priv->needs_allocation))
8206     {
8207       ClutterActor *stage = _clutter_actor_get_stage_internal (self);
8208
8209       /* do not queue a relayout on an unparented actor */
8210       if (stage)
8211         _clutter_stage_maybe_relayout (stage);
8212     }
8213
8214   /* commenting out the code above and just keeping this assigment
8215    * implements 3)
8216    */
8217   *box = self->priv->allocation;
8218 }
8219
8220 /**
8221  * clutter_actor_get_allocation_geometry:
8222  * @self: A #ClutterActor
8223  * @geom: (out): allocation geometry in pixels
8224  *
8225  * Gets the layout box an actor has been assigned.  The allocation can
8226  * only be assumed valid inside a paint() method; anywhere else, it
8227  * may be out-of-date.
8228  *
8229  * An allocation does not incorporate the actor's scale or anchor point;
8230  * those transformations do not affect layout, only rendering.
8231  *
8232  * The returned rectangle is in pixels.
8233  *
8234  * Since: 0.8
8235  */
8236 void
8237 clutter_actor_get_allocation_geometry (ClutterActor    *self,
8238                                        ClutterGeometry *geom)
8239 {
8240   ClutterActorBox box;
8241
8242   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8243   g_return_if_fail (geom != NULL);
8244
8245   clutter_actor_get_allocation_box (self, &box);
8246
8247   geom->x = CLUTTER_NEARBYINT (clutter_actor_box_get_x (&box));
8248   geom->y = CLUTTER_NEARBYINT (clutter_actor_box_get_y (&box));
8249   geom->width = CLUTTER_NEARBYINT (clutter_actor_box_get_width (&box));
8250   geom->height = CLUTTER_NEARBYINT (clutter_actor_box_get_height (&box));
8251 }
8252
8253 static void
8254 clutter_actor_update_constraints (ClutterActor    *self,
8255                                   ClutterActorBox *allocation)
8256 {
8257   ClutterActorPrivate *priv = self->priv;
8258   const GList *constraints, *l;
8259
8260   if (priv->constraints == NULL)
8261     return;
8262
8263   constraints = _clutter_meta_group_peek_metas (priv->constraints);
8264   for (l = constraints; l != NULL; l = l->next)
8265     {
8266       ClutterConstraint *constraint = l->data;
8267       ClutterActorMeta *meta = l->data;
8268
8269       if (clutter_actor_meta_get_enabled (meta))
8270         {
8271           _clutter_constraint_update_allocation (constraint,
8272                                                  self,
8273                                                  allocation);
8274
8275           CLUTTER_NOTE (LAYOUT,
8276                         "Allocation of '%s' after constraint '%s': "
8277                         "{ %.2f, %.2f, %.2f, %.2f }",
8278                         _clutter_actor_get_debug_name (self),
8279                         _clutter_actor_meta_get_debug_name (meta),
8280                         allocation->x1,
8281                         allocation->y1,
8282                         allocation->x2,
8283                         allocation->y2);
8284         }
8285     }
8286 }
8287
8288 /*< private >
8289  * clutter_actor_adjust_allocation:
8290  * @self: a #ClutterActor
8291  * @allocation: (inout): the allocation to adjust
8292  *
8293  * Adjusts the passed allocation box taking into account the actor's
8294  * layout information, like alignment, expansion, and margin.
8295  */
8296 static void
8297 clutter_actor_adjust_allocation (ClutterActor    *self,
8298                                  ClutterActorBox *allocation)
8299 {
8300   ClutterActorBox adj_allocation;
8301   float alloc_width, alloc_height;
8302   float min_width, min_height;
8303   float nat_width, nat_height;
8304   ClutterRequestMode req_mode;
8305
8306   adj_allocation = *allocation;
8307
8308   clutter_actor_box_get_size (allocation, &alloc_width, &alloc_height);
8309
8310   /* we want to hit the cache, so we use the public API */
8311   req_mode = clutter_actor_get_request_mode (self);
8312
8313   if (req_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
8314     {
8315       clutter_actor_get_preferred_width (self, -1,
8316                                          &min_width,
8317                                          &nat_width);
8318       clutter_actor_get_preferred_height (self, alloc_width,
8319                                           &min_height,
8320                                           &nat_height);
8321     }
8322   else if (req_mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
8323     {
8324       clutter_actor_get_preferred_height (self, -1,
8325                                           &min_height,
8326                                           &nat_height);
8327       clutter_actor_get_preferred_height (self, alloc_height,
8328                                           &min_width,
8329                                           &nat_width);
8330     }
8331
8332 #ifdef CLUTTER_ENABLE_DEBUG
8333   /* warn about underallocations */
8334   if (_clutter_diagnostic_enabled () &&
8335       (floorf (min_width - alloc_width) > 0 ||
8336        floorf (min_height - alloc_height) > 0))
8337     {
8338       ClutterActor *parent = clutter_actor_get_parent (self);
8339
8340       /* the only actors that are allowed to be underallocated are the Stage,
8341        * as it doesn't have an implicit size, and Actors that specifically
8342        * told us that they want to opt-out from layout control mechanisms
8343        * through the NO_LAYOUT escape hatch.
8344        */
8345       if (parent != NULL &&
8346           !(self->flags & CLUTTER_ACTOR_NO_LAYOUT) != 0)
8347         {
8348           g_warning (G_STRLOC ": The actor '%s' is getting an allocation "
8349                      "of %.2f x %.2f from its parent actor '%s', but its "
8350                      "requested minimum size is of %.2f x %.2f",
8351                      _clutter_actor_get_debug_name (self),
8352                      alloc_width, alloc_height,
8353                      _clutter_actor_get_debug_name (parent),
8354                      min_width, min_height);
8355         }
8356     }
8357 #endif
8358
8359   clutter_actor_adjust_width (self,
8360                               &min_width,
8361                               &nat_width,
8362                               &adj_allocation.x1,
8363                               &adj_allocation.x2);
8364
8365   clutter_actor_adjust_height (self,
8366                                &min_height,
8367                                &nat_height,
8368                                &adj_allocation.y1,
8369                                &adj_allocation.y2);
8370
8371   /* we maintain the invariant that an allocation cannot be adjusted
8372    * to be outside the parent-given box
8373    */
8374   if (adj_allocation.x1 < allocation->x1 ||
8375       adj_allocation.y1 < allocation->y1 ||
8376       adj_allocation.x2 > allocation->x2 ||
8377       adj_allocation.y2 > allocation->y2)
8378     {
8379       g_warning (G_STRLOC ": The actor '%s' tried to adjust its allocation "
8380                  "to { %.2f, %.2f, %.2f, %.2f }, which is outside of its "
8381                  "original allocation of { %.2f, %.2f, %.2f, %.2f }",
8382                  _clutter_actor_get_debug_name (self),
8383                  adj_allocation.x1, adj_allocation.y1,
8384                  adj_allocation.x2 - adj_allocation.x1,
8385                  adj_allocation.y2 - adj_allocation.y1,
8386                  allocation->x1, allocation->y1,
8387                  allocation->x2 - allocation->x1,
8388                  allocation->y2 - allocation->y1);
8389       return;
8390     }
8391
8392   *allocation = adj_allocation;
8393 }
8394
8395 /**
8396  * clutter_actor_allocate:
8397  * @self: A #ClutterActor
8398  * @box: new allocation of the actor, in parent-relative coordinates
8399  * @flags: flags that control the allocation
8400  *
8401  * Called by the parent of an actor to assign the actor its size.
8402  * Should never be called by applications (except when implementing
8403  * a container or layout manager).
8404  *
8405  * Actors can know from their allocation box whether they have moved
8406  * with respect to their parent actor. The @flags parameter describes
8407  * additional information about the allocation, for instance whether
8408  * the parent has moved with respect to the stage, for example because
8409  * a grandparent's origin has moved.
8410  *
8411  * Since: 0.8
8412  */
8413 void
8414 clutter_actor_allocate (ClutterActor           *self,
8415                         const ClutterActorBox  *box,
8416                         ClutterAllocationFlags  flags)
8417 {
8418   ClutterActorPrivate *priv;
8419   ClutterActorClass *klass;
8420   ClutterActorBox old_allocation, real_allocation;
8421   gboolean origin_changed, child_moved, size_changed;
8422   gboolean stage_allocation_changed;
8423
8424   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8425   if (G_UNLIKELY (_clutter_actor_get_stage_internal (self) == NULL))
8426     {
8427       g_warning ("Spurious clutter_actor_allocate called for actor %p/%s "
8428                  "which isn't a descendent of the stage!\n",
8429                  self, _clutter_actor_get_debug_name (self));
8430       return;
8431     }
8432
8433   priv = self->priv;
8434
8435   old_allocation = priv->allocation;
8436   real_allocation = *box;
8437
8438   /* constraints are allowed to modify the allocation only here; we do
8439    * this prior to all the other checks so that we can bail out if the
8440    * allocation did not change
8441    */
8442   clutter_actor_update_constraints (self, &real_allocation);
8443
8444   /* adjust the allocation depending on the align/margin properties */
8445   clutter_actor_adjust_allocation (self, &real_allocation);
8446
8447   if (real_allocation.x2 < real_allocation.x1 ||
8448       real_allocation.y2 < real_allocation.y1)
8449     {
8450       g_warning (G_STRLOC ": Actor '%s' tried to allocate a size of %.2f x %.2f",
8451                  _clutter_actor_get_debug_name (self),
8452                  real_allocation.x2 - real_allocation.x1,
8453                  real_allocation.y2 - real_allocation.y1);
8454     }
8455
8456   /* we allow 0-sized actors, but not negative-sized ones */
8457   real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
8458   real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
8459
8460   origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
8461
8462   child_moved = (real_allocation.x1 != old_allocation.x1 ||
8463                  real_allocation.y1 != old_allocation.y1);
8464
8465   size_changed = (real_allocation.x2 != old_allocation.x2 ||
8466                   real_allocation.y2 != old_allocation.y2);
8467
8468   if (origin_changed || child_moved || size_changed)
8469     stage_allocation_changed = TRUE;
8470   else
8471     stage_allocation_changed = FALSE;
8472
8473   /* If we get an allocation "out of the blue"
8474    * (we did not queue relayout), then we want to
8475    * ignore it. But if we have needs_allocation set,
8476    * we want to guarantee that allocate() virtual
8477    * method is always called, i.e. that queue_relayout()
8478    * always results in an allocate() invocation on
8479    * an actor.
8480    *
8481    * The optimization here is to avoid re-allocating
8482    * actors that did not queue relayout and were
8483    * not moved.
8484    */
8485   if (!priv->needs_allocation && !stage_allocation_changed)
8486     {
8487       CLUTTER_NOTE (LAYOUT, "No allocation needed");
8488       return;
8489     }
8490
8491   /* When ABSOLUTE_ORIGIN_CHANGED is passed in to
8492    * clutter_actor_allocate(), it indicates whether the parent has its
8493    * absolute origin moved; when passed in to ClutterActor::allocate()
8494    * virtual method though, it indicates whether the child has its
8495    * absolute origin moved.  So we set it when child_moved is TRUE
8496    */
8497   if (child_moved)
8498     flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
8499
8500   CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8501
8502   CLUTTER_NOTE (LAYOUT, "Calling %s::allocate()",
8503                 _clutter_actor_get_debug_name (self));
8504
8505   klass = CLUTTER_ACTOR_GET_CLASS (self);
8506   klass->allocate (self, &real_allocation, flags);
8507
8508   CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
8509
8510   if (stage_allocation_changed)
8511     clutter_actor_queue_redraw (self);
8512 }
8513
8514 /**
8515  * clutter_actor_set_allocation:
8516  * @self: a #ClutterActor
8517  * @box: a #ClutterActorBox
8518  * @flags: allocation flags
8519  *
8520  * Stores the allocation of @self as defined by @box.
8521  *
8522  * This function can only be called from within the implementation of
8523  * the #ClutterActorClass.allocate() virtual function.
8524  *
8525  * The allocation should have been adjusted to take into account constraints,
8526  * alignment, and margin properties. If you are implementing a #ClutterActor
8527  * subclass that provides its own layout management policy for its children
8528  * instead of using a #ClutterLayoutManager delegate, you should not call
8529  * this function on the children of @self; instead, you should call
8530  * clutter_actor_allocate(), which will adjust the allocation box for
8531  * you.
8532  *
8533  * This function should only be used by subclasses of #ClutterActor
8534  * that wish to store their allocation but cannot chain up to the
8535  * parent's implementation; the default implementation of the
8536  * #ClutterActorClass.allocate() virtual function will call this
8537  * function.
8538  *
8539  * It is important to note that, while chaining up was the recommended
8540  * behaviour for #ClutterActor subclasses prior to the introduction of
8541  * this function, it is recommended to call clutter_actor_set_allocation()
8542  * instead.
8543  *
8544  * If the #ClutterActor is using a #ClutterLayoutManager delegate object
8545  * to handle the allocation of its children, this function will call
8546  * the clutter_layout_manager_allocate() function only if the
8547  * %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
8548  * expected that the subclass will call clutter_layout_manager_allocate()
8549  * by itself. For instance, the following code:
8550  *
8551  * |[
8552  * static void
8553  * my_actor_allocate (ClutterActor *actor,
8554  *                    const ClutterActorBox *allocation,
8555  *                    ClutterAllocationFlags flags)
8556  * {
8557  *   ClutterActorBox new_alloc;
8558  *   ClutterAllocationFlags new_flags;
8559  *
8560  *   adjust_allocation (allocation, &amp;new_alloc);
8561  *
8562  *   new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
8563  *
8564  *   /&ast; this will use the layout manager set on the actor &ast;/
8565  *   clutter_actor_set_allocation (actor, &amp;new_alloc, new_flags);
8566  * }
8567  * ]|
8568  *
8569  * is equivalent to this:
8570  *
8571  * |[
8572  * static void
8573  * my_actor_allocate (ClutterActor *actor,
8574  *                    const ClutterActorBox *allocation,
8575  *                    ClutterAllocationFlags flags)
8576  * {
8577  *   ClutterLayoutManager *layout;
8578  *   ClutterActorBox new_alloc;
8579  *
8580  *   adjust_allocation (allocation, &amp;new_alloc);
8581  *
8582  *   clutter_actor_set_allocation (actor, &amp;new_alloc, flags);
8583  *
8584  *   layout = clutter_actor_get_layout_manager (actor);
8585  *   clutter_layout_manager_allocate (layout,
8586  *                                    CLUTTER_CONTAINER (actor),
8587  *                                    &amp;new_alloc,
8588  *                                    flags);
8589  * }
8590  * ]|
8591  *
8592  * Since: 1.10
8593  */
8594 void
8595 clutter_actor_set_allocation (ClutterActor           *self,
8596                               const ClutterActorBox  *box,
8597                               ClutterAllocationFlags  flags)
8598 {
8599   ClutterActorPrivate *priv;
8600   gboolean changed;
8601
8602   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8603   g_return_if_fail (box != NULL);
8604
8605   if (G_UNLIKELY (!CLUTTER_ACTOR_IN_RELAYOUT (self)))
8606     {
8607       g_critical (G_STRLOC ": The clutter_actor_set_allocation() function "
8608                   "can only be called from within the implementation of "
8609                   "the ClutterActor::allocate() virtual function.");
8610       return;
8611     }
8612
8613   priv = self->priv;
8614
8615   g_object_freeze_notify (G_OBJECT (self));
8616
8617   changed = clutter_actor_set_allocation_internal (self, box, flags);
8618
8619   /* we allocate our children before we notify changes in our geometry,
8620    * so that people connecting to properties will be able to get valid
8621    * data out of the sub-tree of the scene graph that has this actor at
8622    * the root.
8623    */
8624   clutter_actor_maybe_layout_children (self, box, flags);
8625
8626   if (changed)
8627     {
8628       ClutterActorBox signal_box = priv->allocation;
8629       ClutterAllocationFlags signal_flags = priv->allocation_flags;
8630
8631       g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
8632                      &signal_box,
8633                      signal_flags);
8634     }
8635
8636   g_object_thaw_notify (G_OBJECT (self));
8637 }
8638
8639 /**
8640  * clutter_actor_set_geometry:
8641  * @self: A #ClutterActor
8642  * @geometry: A #ClutterGeometry
8643  *
8644  * Sets the actor's fixed position and forces its minimum and natural
8645  * size, in pixels. This means the untransformed actor will have the
8646  * given geometry. This is the same as calling clutter_actor_set_position()
8647  * and clutter_actor_set_size().
8648  *
8649  * Deprecated: 1.10: Use clutter_actor_set_position() and
8650  *   clutter_actor_set_size() instead.
8651  */
8652 void
8653 clutter_actor_set_geometry (ClutterActor          *self,
8654                             const ClutterGeometry *geometry)
8655 {
8656   g_object_freeze_notify (G_OBJECT (self));
8657
8658   clutter_actor_set_position (self, geometry->x, geometry->y);
8659   clutter_actor_set_size (self, geometry->width, geometry->height);
8660
8661   g_object_thaw_notify (G_OBJECT (self));
8662 }
8663
8664 /**
8665  * clutter_actor_get_geometry:
8666  * @self: A #ClutterActor
8667  * @geometry: (out caller-allocates): A location to store actors #ClutterGeometry
8668  *
8669  * Gets the size and position of an actor relative to its parent
8670  * actor. This is the same as calling clutter_actor_get_position() and
8671  * clutter_actor_get_size(). It tries to "do what you mean" and get the
8672  * requested size and position if the actor's allocation is invalid.
8673  *
8674  * Deprecated: 1.10: Use clutter_actor_get_position() and
8675  *   clutter_actor_get_size(), or clutter_actor_get_allocation_geometry()
8676  *   instead.
8677  */
8678 void
8679 clutter_actor_get_geometry (ClutterActor    *self,
8680                             ClutterGeometry *geometry)
8681 {
8682   gfloat x, y, width, height;
8683
8684   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8685   g_return_if_fail (geometry != NULL);
8686
8687   clutter_actor_get_position (self, &x, &y);
8688   clutter_actor_get_size (self, &width, &height);
8689
8690   geometry->x = (int) x;
8691   geometry->y = (int) y;
8692   geometry->width = (int) width;
8693   geometry->height = (int) height;
8694 }
8695
8696 /**
8697  * clutter_actor_set_position:
8698  * @self: A #ClutterActor
8699  * @x: New left position of actor in pixels.
8700  * @y: New top position of actor in pixels.
8701  *
8702  * Sets the actor's fixed position in pixels relative to any parent
8703  * actor.
8704  *
8705  * If a layout manager is in use, this position will override the
8706  * layout manager and force a fixed position.
8707  */
8708 void
8709 clutter_actor_set_position (ClutterActor *self,
8710                             gfloat        x,
8711                             gfloat        y)
8712 {
8713   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8714
8715   g_object_freeze_notify (G_OBJECT (self));
8716
8717   clutter_actor_set_x (self, x);
8718   clutter_actor_set_y (self, y);
8719
8720   g_object_thaw_notify (G_OBJECT (self));
8721 }
8722
8723 /**
8724  * clutter_actor_get_fixed_position_set:
8725  * @self: A #ClutterActor
8726  *
8727  * Checks whether an actor has a fixed position set (and will thus be
8728  * unaffected by any layout manager).
8729  *
8730  * Return value: %TRUE if the fixed position is set on the actor
8731  *
8732  * Since: 0.8
8733  */
8734 gboolean
8735 clutter_actor_get_fixed_position_set (ClutterActor *self)
8736 {
8737   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
8738
8739   return self->priv->position_set;
8740 }
8741
8742 /**
8743  * clutter_actor_set_fixed_position_set:
8744  * @self: A #ClutterActor
8745  * @is_set: whether to use fixed position
8746  *
8747  * Sets whether an actor has a fixed position set (and will thus be
8748  * unaffected by any layout manager).
8749  *
8750  * Since: 0.8
8751  */
8752 void
8753 clutter_actor_set_fixed_position_set (ClutterActor *self,
8754                                       gboolean      is_set)
8755 {
8756   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8757
8758   if (self->priv->position_set == (is_set != FALSE))
8759     return;
8760
8761   self->priv->position_set = is_set != FALSE;
8762   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIXED_POSITION_SET]);
8763
8764   clutter_actor_queue_relayout (self);
8765 }
8766
8767 /**
8768  * clutter_actor_move_by:
8769  * @self: A #ClutterActor
8770  * @dx: Distance to move Actor on X axis.
8771  * @dy: Distance to move Actor on Y axis.
8772  *
8773  * Moves an actor by the specified distance relative to its current
8774  * position in pixels.
8775  *
8776  * This function modifies the fixed position of an actor and thus removes
8777  * it from any layout management. Another way to move an actor is with an
8778  * anchor point, see clutter_actor_set_anchor_point().
8779  *
8780  * Since: 0.2
8781  */
8782 void
8783 clutter_actor_move_by (ClutterActor *self,
8784                        gfloat        dx,
8785                        gfloat        dy)
8786 {
8787   const ClutterLayoutInfo *info;
8788   gfloat x, y;
8789
8790   g_return_if_fail (CLUTTER_IS_ACTOR (self));
8791
8792   info = _clutter_actor_get_layout_info_or_defaults (self);
8793   x = info->fixed_x;
8794   y = info->fixed_y;
8795
8796   clutter_actor_set_position (self, x + dx, y + dy);
8797 }
8798
8799 static void
8800 clutter_actor_set_min_width (ClutterActor *self,
8801                              gfloat        min_width)
8802 {
8803   ClutterActorPrivate *priv = self->priv;
8804   ClutterActorBox old = { 0, };
8805   ClutterLayoutInfo *info;
8806
8807   /* if we are setting the size on a top-level actor and the
8808    * backend only supports static top-levels (e.g. framebuffers)
8809    * then we ignore the passed value and we override it with
8810    * the stage implementation's preferred size.
8811    */
8812   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8813       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8814     return;
8815
8816   info = _clutter_actor_get_layout_info (self);
8817
8818   if (priv->min_width_set && min_width == info->min_width)
8819     return;
8820
8821   g_object_freeze_notify (G_OBJECT (self));
8822
8823   clutter_actor_store_old_geometry (self, &old);
8824
8825   info->min_width = min_width;
8826   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH]);
8827   clutter_actor_set_min_width_set (self, TRUE);
8828
8829   clutter_actor_notify_if_geometry_changed (self, &old);
8830
8831   g_object_thaw_notify (G_OBJECT (self));
8832
8833   clutter_actor_queue_relayout (self);
8834 }
8835
8836 static void
8837 clutter_actor_set_min_height (ClutterActor *self,
8838                               gfloat        min_height)
8839
8840 {
8841   ClutterActorPrivate *priv = self->priv;
8842   ClutterActorBox old = { 0, };
8843   ClutterLayoutInfo *info;
8844
8845   /* if we are setting the size on a top-level actor and the
8846    * backend only supports static top-levels (e.g. framebuffers)
8847    * then we ignore the passed value and we override it with
8848    * the stage implementation's preferred size.
8849    */
8850   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8851       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8852     return;
8853
8854   info = _clutter_actor_get_layout_info (self);
8855
8856   if (priv->min_height_set && min_height == info->min_height)
8857     return;
8858
8859   g_object_freeze_notify (G_OBJECT (self));
8860
8861   clutter_actor_store_old_geometry (self, &old);
8862
8863   info->min_height = min_height;
8864   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT]);
8865   clutter_actor_set_min_height_set (self, TRUE);
8866
8867   clutter_actor_notify_if_geometry_changed (self, &old);
8868
8869   g_object_thaw_notify (G_OBJECT (self));
8870
8871   clutter_actor_queue_relayout (self);
8872 }
8873
8874 static void
8875 clutter_actor_set_natural_width (ClutterActor *self,
8876                                  gfloat        natural_width)
8877 {
8878   ClutterActorPrivate *priv = self->priv;
8879   ClutterActorBox old = { 0, };
8880   ClutterLayoutInfo *info;
8881
8882   /* if we are setting the size on a top-level actor and the
8883    * backend only supports static top-levels (e.g. framebuffers)
8884    * then we ignore the passed value and we override it with
8885    * the stage implementation's preferred size.
8886    */
8887   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8888       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8889     return;
8890
8891   info = _clutter_actor_get_layout_info (self);
8892
8893   if (priv->natural_width_set && natural_width == info->natural_width)
8894     return;
8895
8896   g_object_freeze_notify (G_OBJECT (self));
8897
8898   clutter_actor_store_old_geometry (self, &old);
8899
8900   info->natural_width = natural_width;
8901   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH]);
8902   clutter_actor_set_natural_width_set (self, TRUE);
8903
8904   clutter_actor_notify_if_geometry_changed (self, &old);
8905
8906   g_object_thaw_notify (G_OBJECT (self));
8907
8908   clutter_actor_queue_relayout (self);
8909 }
8910
8911 static void
8912 clutter_actor_set_natural_height (ClutterActor *self,
8913                                   gfloat        natural_height)
8914 {
8915   ClutterActorPrivate *priv = self->priv;
8916   ClutterActorBox old = { 0, };
8917   ClutterLayoutInfo *info;
8918
8919   /* if we are setting the size on a top-level actor and the
8920    * backend only supports static top-levels (e.g. framebuffers)
8921    * then we ignore the passed value and we override it with
8922    * the stage implementation's preferred size.
8923    */
8924   if (CLUTTER_ACTOR_IS_TOPLEVEL (self) &&
8925       clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
8926     return;
8927
8928   info = _clutter_actor_get_layout_info (self);
8929
8930   if (priv->natural_height_set && natural_height == info->natural_height)
8931     return;
8932
8933   g_object_freeze_notify (G_OBJECT (self));
8934
8935   clutter_actor_store_old_geometry (self, &old);
8936
8937   info->natural_height = natural_height;
8938   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT]);
8939   clutter_actor_set_natural_height_set (self, TRUE);
8940
8941   clutter_actor_notify_if_geometry_changed (self, &old);
8942
8943   g_object_thaw_notify (G_OBJECT (self));
8944
8945   clutter_actor_queue_relayout (self);
8946 }
8947
8948 static void
8949 clutter_actor_set_min_width_set (ClutterActor *self,
8950                                  gboolean      use_min_width)
8951 {
8952   ClutterActorPrivate *priv = self->priv;
8953   ClutterActorBox old = { 0, };
8954
8955   if (priv->min_width_set == (use_min_width != FALSE))
8956     return;
8957
8958   clutter_actor_store_old_geometry (self, &old);
8959
8960   priv->min_width_set = use_min_width != FALSE;
8961   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_WIDTH_SET]);
8962
8963   clutter_actor_notify_if_geometry_changed (self, &old);
8964
8965   clutter_actor_queue_relayout (self);
8966 }
8967
8968 static void
8969 clutter_actor_set_min_height_set (ClutterActor *self,
8970                                   gboolean      use_min_height)
8971 {
8972   ClutterActorPrivate *priv = self->priv;
8973   ClutterActorBox old = { 0, };
8974
8975   if (priv->min_height_set == (use_min_height != FALSE))
8976     return;
8977
8978   clutter_actor_store_old_geometry (self, &old);
8979
8980   priv->min_height_set = use_min_height != FALSE;
8981   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_MIN_HEIGHT_SET]);
8982
8983   clutter_actor_notify_if_geometry_changed (self, &old);
8984
8985   clutter_actor_queue_relayout (self);
8986 }
8987
8988 static void
8989 clutter_actor_set_natural_width_set (ClutterActor *self,
8990                                      gboolean      use_natural_width)
8991 {
8992   ClutterActorPrivate *priv = self->priv;
8993   ClutterActorBox old = { 0, };
8994
8995   if (priv->natural_width_set == (use_natural_width != FALSE))
8996     return;
8997
8998   clutter_actor_store_old_geometry (self, &old);
8999
9000   priv->natural_width_set = use_natural_width != FALSE;
9001   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_WIDTH_SET]);
9002
9003   clutter_actor_notify_if_geometry_changed (self, &old);
9004
9005   clutter_actor_queue_relayout (self);
9006 }
9007
9008 static void
9009 clutter_actor_set_natural_height_set (ClutterActor *self,
9010                                       gboolean      use_natural_height)
9011 {
9012   ClutterActorPrivate *priv = self->priv;
9013   ClutterActorBox old = { 0, };
9014
9015   if (priv->natural_height_set == (use_natural_height != FALSE))
9016     return;
9017
9018   clutter_actor_store_old_geometry (self, &old);
9019
9020   priv->natural_height_set = use_natural_height != FALSE;
9021   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NATURAL_HEIGHT_SET]);
9022
9023   clutter_actor_notify_if_geometry_changed (self, &old);
9024
9025   clutter_actor_queue_relayout (self);
9026 }
9027
9028 /**
9029  * clutter_actor_set_request_mode:
9030  * @self: a #ClutterActor
9031  * @mode: the request mode
9032  *
9033  * Sets the geometry request mode of @self.
9034  *
9035  * The @mode determines the order for invoking
9036  * clutter_actor_get_preferred_width() and
9037  * clutter_actor_get_preferred_height()
9038  *
9039  * Since: 1.2
9040  */
9041 void
9042 clutter_actor_set_request_mode (ClutterActor       *self,
9043                                 ClutterRequestMode  mode)
9044 {
9045   ClutterActorPrivate *priv;
9046
9047   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9048
9049   priv = self->priv;
9050
9051   if (priv->request_mode == mode)
9052     return;
9053
9054   priv->request_mode = mode;
9055
9056   priv->needs_width_request = TRUE;
9057   priv->needs_height_request = TRUE;
9058
9059   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_REQUEST_MODE]);
9060
9061   clutter_actor_queue_relayout (self);
9062 }
9063
9064 /**
9065  * clutter_actor_get_request_mode:
9066  * @self: a #ClutterActor
9067  *
9068  * Retrieves the geometry request mode of @self
9069  *
9070  * Return value: the request mode for the actor
9071  *
9072  * Since: 1.2
9073  */
9074 ClutterRequestMode
9075 clutter_actor_get_request_mode (ClutterActor *self)
9076 {
9077   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
9078                         CLUTTER_REQUEST_HEIGHT_FOR_WIDTH);
9079
9080   return self->priv->request_mode;
9081 }
9082
9083 /* variant of set_width() without checks and without notification
9084  * freeze+thaw, for internal usage only
9085  */
9086 static inline void
9087 clutter_actor_set_width_internal (ClutterActor *self,
9088                                   gfloat        width)
9089 {
9090   if (width >= 0)
9091     {
9092       /* the Stage will use the :min-width to control the minimum
9093        * width to be resized to, so we should not be setting it
9094        * along with the :natural-width
9095        */
9096       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9097         clutter_actor_set_min_width (self, width);
9098
9099       clutter_actor_set_natural_width (self, width);
9100     }
9101   else
9102     {
9103       /* we only unset the :natural-width for the Stage */
9104       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9105         clutter_actor_set_min_width_set (self, FALSE);
9106
9107       clutter_actor_set_natural_width_set (self, FALSE);
9108     }
9109 }
9110
9111 /* variant of set_height() without checks and without notification
9112  * freeze+thaw, for internal usage only
9113  */
9114 static inline void
9115 clutter_actor_set_height_internal (ClutterActor *self,
9116                                    gfloat        height)
9117 {
9118   if (height >= 0)
9119     {
9120       /* see the comment above in set_width_internal() */
9121       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9122         clutter_actor_set_min_height (self, height);
9123
9124       clutter_actor_set_natural_height (self, height);
9125     }
9126   else
9127     {
9128       /* see the comment above in set_width_internal() */
9129       if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
9130         clutter_actor_set_min_height_set (self, FALSE);
9131
9132       clutter_actor_set_natural_height_set (self, FALSE);
9133     }
9134 }
9135
9136 /**
9137  * clutter_actor_set_size:
9138  * @self: A #ClutterActor
9139  * @width: New width of actor in pixels, or -1
9140  * @height: New height of actor in pixels, or -1
9141  *
9142  * Sets the actor's size request in pixels. This overrides any
9143  * "normal" size request the actor would have. For example
9144  * a text actor might normally request the size of the text;
9145  * this function would force a specific size instead.
9146  *
9147  * If @width and/or @height are -1 the actor will use its
9148  * "normal" size request instead of overriding it, i.e.
9149  * you can "unset" the size with -1.
9150  *
9151  * This function sets or unsets both the minimum and natural size.
9152  */
9153 void
9154 clutter_actor_set_size (ClutterActor *self,
9155                         gfloat        width,
9156                         gfloat        height)
9157 {
9158   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9159
9160   g_object_freeze_notify (G_OBJECT (self));
9161
9162   clutter_actor_set_width (self, width);
9163   clutter_actor_set_height (self, height);
9164
9165   g_object_thaw_notify (G_OBJECT (self));
9166 }
9167
9168 /**
9169  * clutter_actor_get_size:
9170  * @self: A #ClutterActor
9171  * @width: (out) (allow-none): return location for the width, or %NULL.
9172  * @height: (out) (allow-none): return location for the height, or %NULL.
9173  *
9174  * This function tries to "do what you mean" and return
9175  * the size an actor will have. If the actor has a valid
9176  * allocation, the allocation will be returned; otherwise,
9177  * the actors natural size request will be returned.
9178  *
9179  * If you care whether you get the request vs. the allocation, you
9180  * should probably call a different function like
9181  * clutter_actor_get_allocation_box() or
9182  * clutter_actor_get_preferred_width().
9183  *
9184  * Since: 0.2
9185  */
9186 void
9187 clutter_actor_get_size (ClutterActor *self,
9188                         gfloat       *width,
9189                         gfloat       *height)
9190 {
9191   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9192
9193   if (width)
9194     *width = clutter_actor_get_width (self);
9195
9196   if (height)
9197     *height = clutter_actor_get_height (self);
9198 }
9199
9200 /**
9201  * clutter_actor_get_position:
9202  * @self: a #ClutterActor
9203  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9204  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9205  *
9206  * This function tries to "do what you mean" and tell you where the
9207  * actor is, prior to any transformations. Retrieves the fixed
9208  * position of an actor in pixels, if one has been set; otherwise, if
9209  * the allocation is valid, returns the actor's allocated position;
9210  * otherwise, returns 0,0.
9211  *
9212  * The returned position is in pixels.
9213  *
9214  * Since: 0.6
9215  */
9216 void
9217 clutter_actor_get_position (ClutterActor *self,
9218                             gfloat       *x,
9219                             gfloat       *y)
9220 {
9221   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9222
9223   if (x)
9224     *x = clutter_actor_get_x (self);
9225
9226   if (y)
9227     *y = clutter_actor_get_y (self);
9228 }
9229
9230 /**
9231  * clutter_actor_get_transformed_position:
9232  * @self: A #ClutterActor
9233  * @x: (out) (allow-none): return location for the X coordinate, or %NULL
9234  * @y: (out) (allow-none): return location for the Y coordinate, or %NULL
9235  *
9236  * Gets the absolute position of an actor, in pixels relative to the stage.
9237  *
9238  * Since: 0.8
9239  */
9240 void
9241 clutter_actor_get_transformed_position (ClutterActor *self,
9242                                         gfloat       *x,
9243                                         gfloat       *y)
9244 {
9245   ClutterVertex v1;
9246   ClutterVertex v2;
9247
9248   v1.x = v1.y = v1.z = 0;
9249   clutter_actor_apply_transform_to_point (self, &v1, &v2);
9250
9251   if (x)
9252     *x = v2.x;
9253
9254   if (y)
9255     *y = v2.y;
9256 }
9257
9258 /**
9259  * clutter_actor_get_transformed_size:
9260  * @self: A #ClutterActor
9261  * @width: (out) (allow-none): return location for the width, or %NULL
9262  * @height: (out) (allow-none): return location for the height, or %NULL
9263  *
9264  * Gets the absolute size of an actor in pixels, taking into account the
9265  * scaling factors.
9266  *
9267  * If the actor has a valid allocation, the allocated size will be used.
9268  * If the actor has not a valid allocation then the preferred size will
9269  * be transformed and returned.
9270  *
9271  * If you want the transformed allocation, see
9272  * clutter_actor_get_abs_allocation_vertices() instead.
9273  *
9274  * <note>When the actor (or one of its ancestors) is rotated around the
9275  * X or Y axis, it no longer appears as on the stage as a rectangle, but
9276  * as a generic quadrangle; in that case this function returns the size
9277  * of the smallest rectangle that encapsulates the entire quad. Please
9278  * note that in this case no assumptions can be made about the relative
9279  * position of this envelope to the absolute position of the actor, as
9280  * returned by clutter_actor_get_transformed_position(); if you need this
9281  * information, you need to use clutter_actor_get_abs_allocation_vertices()
9282  * to get the coords of the actual quadrangle.</note>
9283  *
9284  * Since: 0.8
9285  */
9286 void
9287 clutter_actor_get_transformed_size (ClutterActor *self,
9288                                     gfloat       *width,
9289                                     gfloat       *height)
9290 {
9291   ClutterActorPrivate *priv;
9292   ClutterVertex v[4];
9293   gfloat x_min, x_max, y_min, y_max;
9294   gint i;
9295
9296   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9297
9298   priv = self->priv;
9299
9300   /* if the actor hasn't been allocated yet, get the preferred
9301    * size and transform that
9302    */
9303   if (priv->needs_allocation)
9304     {
9305       gfloat natural_width, natural_height;
9306       ClutterActorBox box;
9307
9308       /* Make a fake allocation to transform.
9309        *
9310        * NB: _clutter_actor_transform_and_project_box expects a box in
9311        * the actor's coordinate space... */
9312
9313       box.x1 = 0;
9314       box.y1 = 0;
9315
9316       natural_width = natural_height = 0;
9317       clutter_actor_get_preferred_size (self, NULL, NULL,
9318                                         &natural_width,
9319                                         &natural_height);
9320
9321       box.x2 = natural_width;
9322       box.y2 = natural_height;
9323
9324       _clutter_actor_transform_and_project_box (self, &box, v);
9325     }
9326   else
9327     clutter_actor_get_abs_allocation_vertices (self, v);
9328
9329   x_min = x_max = v[0].x;
9330   y_min = y_max = v[0].y;
9331
9332   for (i = 1; i < G_N_ELEMENTS (v); ++i)
9333     {
9334       if (v[i].x < x_min)
9335         x_min = v[i].x;
9336
9337       if (v[i].x > x_max)
9338         x_max = v[i].x;
9339
9340       if (v[i].y < y_min)
9341         y_min = v[i].y;
9342
9343       if (v[i].y > y_max)
9344         y_max = v[i].y;
9345     }
9346
9347   if (width)
9348     *width  = x_max - x_min;
9349
9350   if (height)
9351     *height = y_max - y_min;
9352 }
9353
9354 /**
9355  * clutter_actor_get_width:
9356  * @self: A #ClutterActor
9357  *
9358  * Retrieves the width of a #ClutterActor.
9359  *
9360  * If the actor has a valid allocation, this function will return the
9361  * width of the allocated area given to the actor.
9362  *
9363  * If the actor does not have a valid allocation, this function will
9364  * return the actor's natural width, that is the preferred width of
9365  * the actor.
9366  *
9367  * If you care whether you get the preferred width or the width that
9368  * has been assigned to the actor, you should probably call a different
9369  * function like clutter_actor_get_allocation_box() to retrieve the
9370  * allocated size or clutter_actor_get_preferred_width() to retrieve the
9371  * preferred width.
9372  *
9373  * If an actor has a fixed width, for instance a width that has been
9374  * assigned using clutter_actor_set_width(), the width returned will
9375  * be the same value.
9376  *
9377  * Return value: the width of the actor, in pixels
9378  */
9379 gfloat
9380 clutter_actor_get_width (ClutterActor *self)
9381 {
9382   ClutterActorPrivate *priv;
9383
9384   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9385
9386   priv = self->priv;
9387
9388   if (priv->needs_allocation)
9389     {
9390       gfloat natural_width = 0;
9391
9392       if (self->priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9393         clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9394       else
9395         {
9396           gfloat natural_height = 0;
9397
9398           clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9399           clutter_actor_get_preferred_width (self, natural_height,
9400                                              NULL,
9401                                              &natural_width);
9402         }
9403
9404       return natural_width;
9405     }
9406   else
9407     return priv->allocation.x2 - priv->allocation.x1;
9408 }
9409
9410 /**
9411  * clutter_actor_get_height:
9412  * @self: A #ClutterActor
9413  *
9414  * Retrieves the height of a #ClutterActor.
9415  *
9416  * If the actor has a valid allocation, this function will return the
9417  * height of the allocated area given to the actor.
9418  *
9419  * If the actor does not have a valid allocation, this function will
9420  * return the actor's natural height, that is the preferred height of
9421  * the actor.
9422  *
9423  * If you care whether you get the preferred height or the height that
9424  * has been assigned to the actor, you should probably call a different
9425  * function like clutter_actor_get_allocation_box() to retrieve the
9426  * allocated size or clutter_actor_get_preferred_height() to retrieve the
9427  * preferred height.
9428  *
9429  * If an actor has a fixed height, for instance a height that has been
9430  * assigned using clutter_actor_set_height(), the height returned will
9431  * be the same value.
9432  *
9433  * Return value: the height of the actor, in pixels
9434  */
9435 gfloat
9436 clutter_actor_get_height (ClutterActor *self)
9437 {
9438   ClutterActorPrivate *priv;
9439
9440   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9441
9442   priv = self->priv;
9443
9444   if (priv->needs_allocation)
9445     {
9446       gfloat natural_height = 0;
9447
9448       if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
9449         {
9450           gfloat natural_width = 0;
9451
9452           clutter_actor_get_preferred_width (self, -1, NULL, &natural_width);
9453           clutter_actor_get_preferred_height (self, natural_width,
9454                                               NULL, &natural_height);
9455         }
9456       else
9457         clutter_actor_get_preferred_height (self, -1, NULL, &natural_height);
9458
9459       return natural_height;
9460     }
9461   else
9462     return priv->allocation.y2 - priv->allocation.y1;
9463 }
9464
9465 /**
9466  * clutter_actor_set_width:
9467  * @self: A #ClutterActor
9468  * @width: Requested new width for the actor, in pixels, or -1
9469  *
9470  * Forces a width on an actor, causing the actor's preferred width
9471  * and height (if any) to be ignored.
9472  *
9473  * If @width is -1 the actor will use its preferred width request
9474  * instead of overriding it, i.e. you can "unset" the width with -1.
9475  *
9476  * This function sets both the minimum and natural size of the actor.
9477  *
9478  * since: 0.2
9479  */
9480 void
9481 clutter_actor_set_width (ClutterActor *self,
9482                          gfloat        width)
9483 {
9484   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9485
9486   if (_clutter_actor_get_transition (self, obj_props[PROP_WIDTH]) == NULL)
9487     {
9488       float cur_size;
9489
9490       /* minor optimization: if we don't have a duration
9491        * then we can skip the get_width() below, to avoid
9492        * the chance of going through get_preferred_width()
9493        * just to jump to a new desired width.
9494        */
9495       if (clutter_actor_get_easing_duration (self) == 0)
9496         {
9497           g_object_freeze_notify (G_OBJECT (self));
9498
9499           clutter_actor_set_width_internal (self, width);
9500
9501           g_object_thaw_notify (G_OBJECT (self));
9502
9503           return;
9504         }
9505       else
9506         cur_size = clutter_actor_get_width (self);
9507
9508       _clutter_actor_create_transition (self,
9509                                         obj_props[PROP_WIDTH],
9510                                         cur_size,
9511                                         width);
9512     }
9513   else
9514     _clutter_actor_update_transition (self, obj_props[PROP_WIDTH], width);
9515 }
9516
9517 /**
9518  * clutter_actor_set_height:
9519  * @self: A #ClutterActor
9520  * @height: Requested new height for the actor, in pixels, or -1
9521  *
9522  * Forces a height on an actor, causing the actor's preferred width
9523  * and height (if any) to be ignored.
9524  *
9525  * If @height is -1 the actor will use its preferred height instead of
9526  * overriding it, i.e. you can "unset" the height with -1.
9527  *
9528  * This function sets both the minimum and natural size of the actor.
9529  *
9530  * since: 0.2
9531  */
9532 void
9533 clutter_actor_set_height (ClutterActor *self,
9534                           gfloat        height)
9535 {
9536   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9537
9538   if (_clutter_actor_get_transition (self, obj_props[PROP_HEIGHT]) == NULL)
9539     {
9540       float cur_size;
9541
9542       /* see the comment in clutter_actor_set_width() above */
9543       if (clutter_actor_get_easing_duration (self) == 0)
9544         {
9545           g_object_freeze_notify (G_OBJECT (self));
9546
9547           clutter_actor_set_height_internal (self, height);
9548
9549           g_object_thaw_notify (G_OBJECT (self));
9550
9551           return;
9552         }
9553       else
9554         cur_size = clutter_actor_get_height (self);
9555
9556       _clutter_actor_create_transition (self,
9557                                         obj_props[PROP_HEIGHT],
9558                                         cur_size,
9559                                         height);
9560     }
9561   else
9562     _clutter_actor_update_transition (self, obj_props[PROP_HEIGHT], height);
9563 }
9564
9565 static inline void
9566 clutter_actor_set_x_internal (ClutterActor *self,
9567                               float         x)
9568 {
9569   ClutterActorPrivate *priv = self->priv;
9570   ClutterLayoutInfo *linfo;
9571   ClutterActorBox old = { 0, };
9572
9573   linfo = _clutter_actor_get_layout_info (self);
9574
9575   if (priv->position_set && linfo->fixed_x == x)
9576     return;
9577
9578   clutter_actor_store_old_geometry (self, &old);
9579
9580   linfo->fixed_x = x;
9581   clutter_actor_set_fixed_position_set (self, TRUE);
9582
9583   clutter_actor_notify_if_geometry_changed (self, &old);
9584
9585   clutter_actor_queue_relayout (self);
9586 }
9587
9588 static inline void
9589 clutter_actor_set_y_internal (ClutterActor *self,
9590                               float         y)
9591 {
9592   ClutterActorPrivate *priv = self->priv;
9593   ClutterLayoutInfo *linfo;
9594   ClutterActorBox old = { 0, };
9595
9596   linfo = _clutter_actor_get_layout_info (self);
9597
9598   if (priv->position_set && linfo->fixed_y == y)
9599     return;
9600
9601   clutter_actor_store_old_geometry (self, &old);
9602
9603   linfo->fixed_y = y;
9604   clutter_actor_set_fixed_position_set (self, TRUE);
9605
9606   clutter_actor_notify_if_geometry_changed (self, &old);
9607
9608   clutter_actor_queue_relayout (self);
9609 }
9610
9611 /**
9612  * clutter_actor_set_x:
9613  * @self: a #ClutterActor
9614  * @x: the actor's position on the X axis
9615  *
9616  * Sets the actor's X coordinate, relative to its parent, in pixels.
9617  *
9618  * Overrides any layout manager and forces a fixed position for
9619  * the actor.
9620  *
9621  * The #ClutterActor:x property is animatable.
9622  *
9623  * Since: 0.6
9624  */
9625 void
9626 clutter_actor_set_x (ClutterActor *self,
9627                      gfloat        x)
9628 {
9629   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9630
9631   if (_clutter_actor_get_transition (self, obj_props[PROP_X]) == NULL)
9632     {
9633       float cur_position = clutter_actor_get_x (self);
9634
9635       _clutter_actor_create_transition (self, obj_props[PROP_X],
9636                                         cur_position,
9637                                         x);
9638     }
9639   else
9640     _clutter_actor_update_transition (self, obj_props[PROP_X], x);
9641 }
9642
9643 /**
9644  * clutter_actor_set_y:
9645  * @self: a #ClutterActor
9646  * @y: the actor's position on the Y axis
9647  *
9648  * Sets the actor's Y coordinate, relative to its parent, in pixels.#
9649  *
9650  * Overrides any layout manager and forces a fixed position for
9651  * the actor.
9652  *
9653  * The #ClutterActor:y property is animatable.
9654  *
9655  * Since: 0.6
9656  */
9657 void
9658 clutter_actor_set_y (ClutterActor *self,
9659                      gfloat        y)
9660 {
9661   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9662
9663   if (_clutter_actor_get_transition (self, obj_props[PROP_Y]) == NULL)
9664     {
9665       float cur_position = clutter_actor_get_y (self);
9666
9667       _clutter_actor_create_transition (self, obj_props[PROP_Y],
9668                                         cur_position,
9669                                         y);
9670     }
9671   else
9672     _clutter_actor_update_transition (self, obj_props[PROP_Y], y);
9673 }
9674
9675 /**
9676  * clutter_actor_get_x:
9677  * @self: A #ClutterActor
9678  *
9679  * Retrieves the X coordinate of a #ClutterActor.
9680  *
9681  * This function tries to "do what you mean", by returning the
9682  * correct value depending on the actor's state.
9683  *
9684  * If the actor has a valid allocation, this function will return
9685  * the X coordinate of the origin of the allocation box.
9686  *
9687  * If the actor has any fixed coordinate set using clutter_actor_set_x(),
9688  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9689  * function will return that coordinate.
9690  *
9691  * If both the allocation and a fixed position are missing, this function
9692  * will return 0.
9693  *
9694  * Return value: the X coordinate, in pixels, ignoring any
9695  *   transformation (i.e. scaling, rotation)
9696  */
9697 gfloat
9698 clutter_actor_get_x (ClutterActor *self)
9699 {
9700   ClutterActorPrivate *priv;
9701
9702   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9703
9704   priv = self->priv;
9705
9706   if (priv->needs_allocation)
9707     {
9708       if (priv->position_set)
9709         {
9710           const ClutterLayoutInfo *info;
9711
9712           info = _clutter_actor_get_layout_info_or_defaults (self);
9713
9714           return info->fixed_x;
9715         }
9716       else
9717         return 0;
9718     }
9719   else
9720     return priv->allocation.x1;
9721 }
9722
9723 /**
9724  * clutter_actor_get_y:
9725  * @self: A #ClutterActor
9726  *
9727  * Retrieves the Y coordinate of a #ClutterActor.
9728  *
9729  * This function tries to "do what you mean", by returning the
9730  * correct value depending on the actor's state.
9731  *
9732  * If the actor has a valid allocation, this function will return
9733  * the Y coordinate of the origin of the allocation box.
9734  *
9735  * If the actor has any fixed coordinate set using clutter_actor_set_y(),
9736  * clutter_actor_set_position() or clutter_actor_set_geometry(), this
9737  * function will return that coordinate.
9738  *
9739  * If both the allocation and a fixed position are missing, this function
9740  * will return 0.
9741  *
9742  * Return value: the Y coordinate, in pixels, ignoring any
9743  *   transformation (i.e. scaling, rotation)
9744  */
9745 gfloat
9746 clutter_actor_get_y (ClutterActor *self)
9747 {
9748   ClutterActorPrivate *priv;
9749
9750   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
9751
9752   priv = self->priv;
9753
9754   if (priv->needs_allocation)
9755     {
9756       if (priv->position_set)
9757         {
9758           const ClutterLayoutInfo *info;
9759
9760           info = _clutter_actor_get_layout_info_or_defaults (self);
9761
9762           return info->fixed_y;
9763         }
9764       else
9765         return 0;
9766     }
9767   else
9768     return priv->allocation.y1;
9769 }
9770
9771 /**
9772  * clutter_actor_set_scale:
9773  * @self: A #ClutterActor
9774  * @scale_x: double factor to scale actor by horizontally.
9775  * @scale_y: double factor to scale actor by vertically.
9776  *
9777  * Scales an actor with the given factors. The scaling is relative to
9778  * the scale center and the anchor point. The scale center is
9779  * unchanged by this function and defaults to 0,0.
9780  *
9781  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9782  * animatable.
9783  *
9784  * Since: 0.2
9785  */
9786 void
9787 clutter_actor_set_scale (ClutterActor *self,
9788                          gdouble       scale_x,
9789                          gdouble       scale_y)
9790 {
9791   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9792
9793   g_object_freeze_notify (G_OBJECT (self));
9794
9795   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9796   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9797
9798   g_object_thaw_notify (G_OBJECT (self));
9799 }
9800
9801 /**
9802  * clutter_actor_set_scale_full:
9803  * @self: A #ClutterActor
9804  * @scale_x: double factor to scale actor by horizontally.
9805  * @scale_y: double factor to scale actor by vertically.
9806  * @center_x: X coordinate of the center of the scale.
9807  * @center_y: Y coordinate of the center of the scale
9808  *
9809  * Scales an actor with the given factors around the given center
9810  * point. The center point is specified in pixels relative to the
9811  * anchor point (usually the top left corner of the actor).
9812  *
9813  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties
9814  * are animatable.
9815  *
9816  * Since: 1.0
9817  */
9818 void
9819 clutter_actor_set_scale_full (ClutterActor *self,
9820                               gdouble       scale_x,
9821                               gdouble       scale_y,
9822                               gfloat        center_x,
9823                               gfloat        center_y)
9824 {
9825   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9826
9827   g_object_freeze_notify (G_OBJECT (self));
9828
9829   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9830   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9831   clutter_actor_set_scale_center (self, CLUTTER_X_AXIS, center_x);
9832   clutter_actor_set_scale_center (self, CLUTTER_Y_AXIS, center_y);
9833
9834   g_object_thaw_notify (G_OBJECT (self));
9835 }
9836
9837 /**
9838  * clutter_actor_set_scale_with_gravity:
9839  * @self: A #ClutterActor
9840  * @scale_x: double factor to scale actor by horizontally.
9841  * @scale_y: double factor to scale actor by vertically.
9842  * @gravity: the location of the scale center expressed as a compass
9843  * direction.
9844  *
9845  * Scales an actor with the given factors around the given
9846  * center point. The center point is specified as one of the compass
9847  * directions in #ClutterGravity. For example, setting it to north
9848  * will cause the top of the actor to remain unchanged and the rest of
9849  * the actor to expand left, right and downwards.
9850  *
9851  * The #ClutterActor:scale-x and #ClutterActor:scale-y properties are
9852  * animatable.
9853  *
9854  * Since: 1.0
9855  */
9856 void
9857 clutter_actor_set_scale_with_gravity (ClutterActor   *self,
9858                                       gdouble         scale_x,
9859                                       gdouble         scale_y,
9860                                       ClutterGravity  gravity)
9861 {
9862   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9863
9864   g_object_freeze_notify (G_OBJECT (self));
9865
9866   clutter_actor_set_scale_factor (self, CLUTTER_X_AXIS, scale_x);
9867   clutter_actor_set_scale_factor (self, CLUTTER_Y_AXIS, scale_y);
9868   clutter_actor_set_scale_gravity (self, gravity);
9869
9870   g_object_thaw_notify (G_OBJECT (self));
9871 }
9872
9873 /**
9874  * clutter_actor_get_scale:
9875  * @self: A #ClutterActor
9876  * @scale_x: (out) (allow-none): Location to store horizonal
9877  *   scale factor, or %NULL.
9878  * @scale_y: (out) (allow-none): Location to store vertical
9879  *   scale factor, or %NULL.
9880  *
9881  * Retrieves an actors scale factors.
9882  *
9883  * Since: 0.2
9884  */
9885 void
9886 clutter_actor_get_scale (ClutterActor *self,
9887                          gdouble      *scale_x,
9888                          gdouble      *scale_y)
9889 {
9890   const ClutterTransformInfo *info;
9891
9892   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9893
9894   info = _clutter_actor_get_transform_info_or_defaults (self);
9895
9896   if (scale_x)
9897     *scale_x = info->scale_x;
9898
9899   if (scale_y)
9900     *scale_y = info->scale_y;
9901 }
9902
9903 /**
9904  * clutter_actor_get_scale_center:
9905  * @self: A #ClutterActor
9906  * @center_x: (out) (allow-none): Location to store the X position
9907  *   of the scale center, or %NULL.
9908  * @center_y: (out) (allow-none): Location to store the Y position
9909  *   of the scale center, or %NULL.
9910  *
9911  * Retrieves the scale center coordinate in pixels relative to the top
9912  * left corner of the actor. If the scale center was specified using a
9913  * #ClutterGravity this will calculate the pixel offset using the
9914  * current size of the actor.
9915  *
9916  * Since: 1.0
9917  */
9918 void
9919 clutter_actor_get_scale_center (ClutterActor *self,
9920                                 gfloat       *center_x,
9921                                 gfloat       *center_y)
9922 {
9923   const ClutterTransformInfo *info;
9924
9925   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9926
9927   info = _clutter_actor_get_transform_info_or_defaults (self);
9928
9929   clutter_anchor_coord_get_units (self, &info->scale_center,
9930                                   center_x,
9931                                   center_y,
9932                                   NULL);
9933 }
9934
9935 /**
9936  * clutter_actor_get_scale_gravity:
9937  * @self: A #ClutterActor
9938  *
9939  * Retrieves the scale center as a compass direction. If the scale
9940  * center was specified in pixels or units this will return
9941  * %CLUTTER_GRAVITY_NONE.
9942  *
9943  * Return value: the scale gravity
9944  *
9945  * Since: 1.0
9946  */
9947 ClutterGravity
9948 clutter_actor_get_scale_gravity (ClutterActor *self)
9949 {
9950   const ClutterTransformInfo *info;
9951
9952   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
9953
9954   info = _clutter_actor_get_transform_info_or_defaults (self);
9955
9956   return clutter_anchor_coord_get_gravity (&info->scale_center);
9957 }
9958
9959 static inline void
9960 clutter_actor_set_opacity_internal (ClutterActor *self,
9961                                     guint8        opacity)
9962 {
9963   ClutterActorPrivate *priv = self->priv;
9964
9965   if (priv->opacity != opacity)
9966     {
9967       priv->opacity = opacity;
9968
9969       /* Queue a redraw from the flatten effect so that it can use
9970          its cached image if available instead of having to redraw the
9971          actual actor. If it doesn't end up using the FBO then the
9972          effect is still able to continue the paint anyway. If there
9973          is no flatten effect yet then this is equivalent to queueing
9974          a full redraw */
9975       _clutter_actor_queue_redraw_full (self,
9976                                         0, /* flags */
9977                                         NULL, /* clip */
9978                                         priv->flatten_effect);
9979
9980       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_OPACITY]);
9981     }
9982 }
9983
9984 /**
9985  * clutter_actor_set_opacity:
9986  * @self: A #ClutterActor
9987  * @opacity: New opacity value for the actor.
9988  *
9989  * Sets the actor's opacity, with zero being completely transparent and
9990  * 255 (0xff) being fully opaque.
9991  *
9992  * The #ClutterActor:opacity property is animatable.
9993  */
9994 void
9995 clutter_actor_set_opacity (ClutterActor *self,
9996                            guint8        opacity)
9997 {
9998   g_return_if_fail (CLUTTER_IS_ACTOR (self));
9999
10000   if (_clutter_actor_get_transition (self, obj_props[PROP_OPACITY]) == NULL)
10001     {
10002       _clutter_actor_create_transition (self, obj_props[PROP_OPACITY],
10003                                         self->priv->opacity,
10004                                         opacity);
10005     }
10006   else
10007     _clutter_actor_update_transition (self, obj_props[PROP_OPACITY], opacity);
10008 }
10009
10010 /*
10011  * clutter_actor_get_paint_opacity_internal:
10012  * @self: a #ClutterActor
10013  *
10014  * Retrieves the absolute opacity of the actor, as it appears on the stage
10015  *
10016  * This function does not do type checks
10017  *
10018  * Return value: the absolute opacity of the actor
10019  */
10020 static guint8
10021 clutter_actor_get_paint_opacity_internal (ClutterActor *self)
10022 {
10023   ClutterActorPrivate *priv = self->priv;
10024   ClutterActor *parent;
10025
10026   /* override the top-level opacity to always be 255; even in
10027    * case of ClutterStage:use-alpha being TRUE we want the rest
10028    * of the scene to be painted
10029    */
10030   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
10031     return 255;
10032
10033   if (priv->opacity_override >= 0)
10034     return priv->opacity_override;
10035
10036   parent = priv->parent;
10037
10038   /* Factor in the actual actors opacity with parents */
10039   if (parent != NULL)
10040     {
10041       guint8 opacity = clutter_actor_get_paint_opacity_internal (parent);
10042
10043       if (opacity != 0xff)
10044         return (opacity * priv->opacity) / 0xff;
10045     }
10046
10047   return priv->opacity;
10048
10049 }
10050
10051 /**
10052  * clutter_actor_get_paint_opacity:
10053  * @self: A #ClutterActor
10054  *
10055  * Retrieves the absolute opacity of the actor, as it appears on the stage.
10056  *
10057  * This function traverses the hierarchy chain and composites the opacity of
10058  * the actor with that of its parents.
10059  *
10060  * This function is intended for subclasses to use in the paint virtual
10061  * function, to paint themselves with the correct opacity.
10062  *
10063  * Return value: The actor opacity value.
10064  *
10065  * Since: 0.8
10066  */
10067 guint8
10068 clutter_actor_get_paint_opacity (ClutterActor *self)
10069 {
10070   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10071
10072   return clutter_actor_get_paint_opacity_internal (self);
10073 }
10074
10075 /**
10076  * clutter_actor_get_opacity:
10077  * @self: a #ClutterActor
10078  *
10079  * Retrieves the opacity value of an actor, as set by
10080  * clutter_actor_set_opacity().
10081  *
10082  * For retrieving the absolute opacity of the actor inside a paint
10083  * virtual function, see clutter_actor_get_paint_opacity().
10084  *
10085  * Return value: the opacity of the actor
10086  */
10087 guint8
10088 clutter_actor_get_opacity (ClutterActor *self)
10089 {
10090   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10091
10092   return self->priv->opacity;
10093 }
10094
10095 /**
10096  * clutter_actor_set_offscreen_redirect:
10097  * @self: A #ClutterActor
10098  * @redirect: New offscreen redirect flags for the actor.
10099  *
10100  * Defines the circumstances where the actor should be redirected into
10101  * an offscreen image. The offscreen image is used to flatten the
10102  * actor into a single image while painting for two main reasons.
10103  * Firstly, when the actor is painted a second time without any of its
10104  * contents changing it can simply repaint the cached image without
10105  * descending further down the actor hierarchy. Secondly, it will make
10106  * the opacity look correct even if there are overlapping primitives
10107  * in the actor.
10108  *
10109  * Caching the actor could in some cases be a performance win and in
10110  * some cases be a performance lose so it is important to determine
10111  * which value is right for an actor before modifying this value. For
10112  * example, there is never any reason to flatten an actor that is just
10113  * a single texture (such as a #ClutterTexture) because it is
10114  * effectively already cached in an image so the offscreen would be
10115  * redundant. Also if the actor contains primitives that are far apart
10116  * with a large transparent area in the middle (such as a large
10117  * CluterGroup with a small actor in the top left and a small actor in
10118  * the bottom right) then the cached image will contain the entire
10119  * image of the large area and the paint will waste time blending all
10120  * of the transparent pixels in the middle.
10121  *
10122  * The default method of implementing opacity on a container simply
10123  * forwards on the opacity to all of the children. If the children are
10124  * overlapping then it will appear as if they are two separate glassy
10125  * objects and there will be a break in the color where they
10126  * overlap. By redirecting to an offscreen buffer it will be as if the
10127  * two opaque objects are combined into one and then made transparent
10128  * which is usually what is expected.
10129  *
10130  * The image below demonstrates the difference between redirecting and
10131  * not. The image shows two Clutter groups, each containing a red and
10132  * a green rectangle which overlap. The opacity on the group is set to
10133  * 128 (which is 50%). When the offscreen redirect is not used, the
10134  * red rectangle can be seen through the blue rectangle as if the two
10135  * rectangles were separately transparent. When the redirect is used
10136  * the group as a whole is transparent instead so the red rectangle is
10137  * not visible where they overlap.
10138  *
10139  * <figure id="offscreen-redirect">
10140  *   <title>Sample of using an offscreen redirect for transparency</title>
10141  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
10142  * </figure>
10143  *
10144  * The default value for this property is 0, so we effectively will
10145  * never redirect an actor offscreen by default. This means that there
10146  * are times that transparent actors may look glassy as described
10147  * above. The reason this is the default is because there is a
10148  * performance trade off between quality and performance here. In many
10149  * cases the default form of glassy opacity looks good enough, but if
10150  * it's not you will need to set the
10151  * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable
10152  * redirection for opacity.
10153  *
10154  * Custom actors that don't contain any overlapping primitives are
10155  * recommended to override the has_overlaps() virtual to return %FALSE
10156  * for maximum efficiency.
10157  *
10158  * Since: 1.8
10159  */
10160 void
10161 clutter_actor_set_offscreen_redirect (ClutterActor *self,
10162                                       ClutterOffscreenRedirect redirect)
10163 {
10164   ClutterActorPrivate *priv;
10165
10166   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10167
10168   priv = self->priv;
10169
10170   if (priv->offscreen_redirect != redirect)
10171     {
10172       priv->offscreen_redirect = redirect;
10173
10174       /* Queue a redraw from the effect so that it can use its cached
10175          image if available instead of having to redraw the actual
10176          actor. If it doesn't end up using the FBO then the effect is
10177          still able to continue the paint anyway. If there is no
10178          effect then this is equivalent to queuing a full redraw */
10179       _clutter_actor_queue_redraw_full (self,
10180                                         0, /* flags */
10181                                         NULL, /* clip */
10182                                         priv->flatten_effect);
10183
10184       g_object_notify_by_pspec (G_OBJECT (self),
10185                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
10186     }
10187 }
10188
10189 /**
10190  * clutter_actor_get_offscreen_redirect:
10191  * @self: a #ClutterActor
10192  *
10193  * Retrieves whether to redirect the actor to an offscreen buffer, as
10194  * set by clutter_actor_set_offscreen_redirect().
10195  *
10196  * Return value: the value of the offscreen-redirect property of the actor
10197  *
10198  * Since: 1.8
10199  */
10200 ClutterOffscreenRedirect
10201 clutter_actor_get_offscreen_redirect (ClutterActor *self)
10202 {
10203   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10204
10205   return self->priv->offscreen_redirect;
10206 }
10207
10208 /**
10209  * clutter_actor_set_name:
10210  * @self: A #ClutterActor
10211  * @name: Textual tag to apply to actor
10212  *
10213  * Sets the given name to @self. The name can be used to identify
10214  * a #ClutterActor.
10215  */
10216 void
10217 clutter_actor_set_name (ClutterActor *self,
10218                         const gchar  *name)
10219 {
10220   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10221
10222   g_free (self->priv->name);
10223   self->priv->name = g_strdup (name);
10224
10225   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_NAME]);
10226 }
10227
10228 /**
10229  * clutter_actor_get_name:
10230  * @self: A #ClutterActor
10231  *
10232  * Retrieves the name of @self.
10233  *
10234  * Return value: the name of the actor, or %NULL. The returned string is
10235  *   owned by the actor and should not be modified or freed.
10236  */
10237 const gchar *
10238 clutter_actor_get_name (ClutterActor *self)
10239 {
10240   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10241
10242   return self->priv->name;
10243 }
10244
10245 /**
10246  * clutter_actor_get_gid:
10247  * @self: A #ClutterActor
10248  *
10249  * Retrieves the unique id for @self.
10250  *
10251  * Return value: Globally unique value for this object instance.
10252  *
10253  * Since: 0.6
10254  *
10255  * Deprecated: 1.8: The id is not used any longer.
10256  */
10257 guint32
10258 clutter_actor_get_gid (ClutterActor *self)
10259 {
10260   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10261
10262   return self->priv->id;
10263 }
10264
10265 static inline void
10266 clutter_actor_set_depth_internal (ClutterActor *self,
10267                                   float         depth)
10268 {
10269   ClutterTransformInfo *info;
10270
10271   info = _clutter_actor_get_transform_info (self);
10272
10273   if (info->depth != depth)
10274     {
10275       /* Sets Z value - XXX 2.0: should we invert? */
10276       info->depth = depth;
10277
10278       self->priv->transform_valid = FALSE;
10279
10280       /* FIXME - remove this crap; sadly, there are still containers
10281        * in Clutter that depend on this utter brain damage
10282        */
10283       clutter_container_sort_depth_order (CLUTTER_CONTAINER (self));
10284
10285       clutter_actor_queue_redraw (self);
10286
10287       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_DEPTH]);
10288     }
10289 }
10290
10291 /**
10292  * clutter_actor_set_depth:
10293  * @self: a #ClutterActor
10294  * @depth: Z co-ord
10295  *
10296  * Sets the Z coordinate of @self to @depth.
10297  *
10298  * The unit used by @depth is dependant on the perspective setup. See
10299  * also clutter_stage_set_perspective().
10300  */
10301 void
10302 clutter_actor_set_depth (ClutterActor *self,
10303                          gfloat        depth)
10304 {
10305   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10306
10307   if (_clutter_actor_get_transition (self, obj_props[PROP_DEPTH]) == NULL)
10308     {
10309       const ClutterTransformInfo *info;
10310
10311       info = _clutter_actor_get_transform_info_or_defaults (self);
10312
10313       _clutter_actor_create_transition (self, obj_props[PROP_DEPTH],
10314                                         info->depth,
10315                                         depth);
10316     }
10317   else
10318     _clutter_actor_update_transition (self, obj_props[PROP_DEPTH], depth);
10319
10320   clutter_actor_queue_redraw (self);
10321 }
10322
10323 /**
10324  * clutter_actor_get_depth:
10325  * @self: a #ClutterActor
10326  *
10327  * Retrieves the depth of @self.
10328  *
10329  * Return value: the depth of the actor
10330  */
10331 gfloat
10332 clutter_actor_get_depth (ClutterActor *self)
10333 {
10334   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10335
10336   return _clutter_actor_get_transform_info_or_defaults (self)->depth;
10337 }
10338
10339 /**
10340  * clutter_actor_set_rotation:
10341  * @self: a #ClutterActor
10342  * @axis: the axis of rotation
10343  * @angle: the angle of rotation
10344  * @x: X coordinate of the rotation center
10345  * @y: Y coordinate of the rotation center
10346  * @z: Z coordinate of the rotation center
10347  *
10348  * Sets the rotation angle of @self around the given axis.
10349  *
10350  * The rotation center coordinates used depend on the value of @axis:
10351  * <itemizedlist>
10352  *   <listitem><para>%CLUTTER_X_AXIS requires @y and @z</para></listitem>
10353  *   <listitem><para>%CLUTTER_Y_AXIS requires @x and @z</para></listitem>
10354  *   <listitem><para>%CLUTTER_Z_AXIS requires @x and @y</para></listitem>
10355  * </itemizedlist>
10356  *
10357  * The rotation coordinates are relative to the anchor point of the
10358  * actor, set using clutter_actor_set_anchor_point(). If no anchor
10359  * point is set, the upper left corner is assumed as the origin.
10360  *
10361  * Since: 0.8
10362  */
10363 void
10364 clutter_actor_set_rotation (ClutterActor      *self,
10365                             ClutterRotateAxis  axis,
10366                             gdouble            angle,
10367                             gfloat             x,
10368                             gfloat             y,
10369                             gfloat             z)
10370 {
10371   ClutterVertex v;
10372
10373   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10374
10375   v.x = x;
10376   v.y = y;
10377   v.z = z;
10378
10379   g_object_freeze_notify (G_OBJECT (self));
10380
10381   clutter_actor_set_rotation_angle (self, axis, angle);
10382   clutter_actor_set_rotation_center_internal (self, axis, &v);
10383
10384   g_object_thaw_notify (G_OBJECT (self));
10385 }
10386
10387 /**
10388  * clutter_actor_set_z_rotation_from_gravity:
10389  * @self: a #ClutterActor
10390  * @angle: the angle of rotation
10391  * @gravity: the center point of the rotation
10392  *
10393  * Sets the rotation angle of @self around the Z axis using the center
10394  * point specified as a compass point. For example to rotate such that
10395  * the center of the actor remains static you can use
10396  * %CLUTTER_GRAVITY_CENTER. If the actor changes size the center point
10397  * will move accordingly.
10398  *
10399  * Since: 1.0
10400  */
10401 void
10402 clutter_actor_set_z_rotation_from_gravity (ClutterActor   *self,
10403                                            gdouble         angle,
10404                                            ClutterGravity  gravity)
10405 {
10406   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10407
10408   if (gravity == CLUTTER_GRAVITY_NONE)
10409     clutter_actor_set_rotation (self, CLUTTER_Z_AXIS, angle, 0, 0, 0);
10410   else
10411     {
10412       GObject *obj = G_OBJECT (self);
10413       ClutterTransformInfo *info;
10414
10415       info = _clutter_actor_get_transform_info (self);
10416
10417       g_object_freeze_notify (obj);
10418
10419       clutter_actor_set_rotation_angle_internal (self, CLUTTER_Z_AXIS, angle);
10420
10421       clutter_anchor_coord_set_gravity (&info->rz_center, gravity);
10422       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z_GRAVITY]);
10423       g_object_notify_by_pspec (obj, obj_props[PROP_ROTATION_CENTER_Z]);
10424
10425       g_object_thaw_notify (obj);
10426     }
10427 }
10428
10429 /**
10430  * clutter_actor_get_rotation:
10431  * @self: a #ClutterActor
10432  * @axis: the axis of rotation
10433  * @x: (out): return value for the X coordinate of the center of rotation
10434  * @y: (out): return value for the Y coordinate of the center of rotation
10435  * @z: (out): return value for the Z coordinate of the center of rotation
10436  *
10437  * Retrieves the angle and center of rotation on the given axis,
10438  * set using clutter_actor_set_rotation().
10439  *
10440  * Return value: the angle of rotation
10441  *
10442  * Since: 0.8
10443  */
10444 gdouble
10445 clutter_actor_get_rotation (ClutterActor      *self,
10446                             ClutterRotateAxis  axis,
10447                             gfloat            *x,
10448                             gfloat            *y,
10449                             gfloat            *z)
10450 {
10451   const ClutterTransformInfo *info;
10452   const AnchorCoord *anchor_coord;
10453   gdouble retval = 0;
10454
10455   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
10456
10457   info = _clutter_actor_get_transform_info_or_defaults (self);
10458
10459   switch (axis)
10460     {
10461     case CLUTTER_X_AXIS:
10462       anchor_coord = &info->rx_center;
10463       retval = info->rx_angle;
10464       break;
10465
10466     case CLUTTER_Y_AXIS:
10467       anchor_coord = &info->ry_center;
10468       retval = info->ry_angle;
10469       break;
10470
10471     case CLUTTER_Z_AXIS:
10472       anchor_coord = &info->rz_center;
10473       retval = info->rz_angle;
10474       break;
10475
10476     default:
10477       anchor_coord = NULL;
10478       retval = 0.0;
10479       break;
10480     }
10481
10482   clutter_anchor_coord_get_units (self, anchor_coord, x, y, z);
10483
10484   return retval;
10485 }
10486
10487 /**
10488  * clutter_actor_get_z_rotation_gravity:
10489  * @self: A #ClutterActor
10490  *
10491  * Retrieves the center for the rotation around the Z axis as a
10492  * compass direction. If the center was specified in pixels or units
10493  * this will return %CLUTTER_GRAVITY_NONE.
10494  *
10495  * Return value: the Z rotation center
10496  *
10497  * Since: 1.0
10498  */
10499 ClutterGravity
10500 clutter_actor_get_z_rotation_gravity (ClutterActor *self)
10501 {
10502   const ClutterTransformInfo *info;
10503
10504   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0.0);
10505
10506   info = _clutter_actor_get_transform_info_or_defaults (self);
10507
10508   return clutter_anchor_coord_get_gravity (&info->rz_center);
10509 }
10510
10511 /**
10512  * clutter_actor_set_clip:
10513  * @self: A #ClutterActor
10514  * @xoff: X offset of the clip rectangle
10515  * @yoff: Y offset of the clip rectangle
10516  * @width: Width of the clip rectangle
10517  * @height: Height of the clip rectangle
10518  *
10519  * Sets clip area for @self. The clip area is always computed from the
10520  * upper left corner of the actor, even if the anchor point is set
10521  * otherwise.
10522  *
10523  * Since: 0.6
10524  */
10525 void
10526 clutter_actor_set_clip (ClutterActor *self,
10527                         gfloat        xoff,
10528                         gfloat        yoff,
10529                         gfloat        width,
10530                         gfloat        height)
10531 {
10532   ClutterActorPrivate *priv;
10533
10534   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10535
10536   priv = self->priv;
10537
10538   if (priv->has_clip &&
10539       priv->clip.x == xoff &&
10540       priv->clip.y == yoff &&
10541       priv->clip.width == width &&
10542       priv->clip.height == height)
10543     return;
10544
10545   priv->clip.x = xoff;
10546   priv->clip.y = yoff;
10547   priv->clip.width = width;
10548   priv->clip.height = height;
10549
10550   priv->has_clip = TRUE;
10551
10552   clutter_actor_queue_redraw (self);
10553
10554   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10555   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CLIP]);
10556 }
10557
10558 /**
10559  * clutter_actor_remove_clip:
10560  * @self: A #ClutterActor
10561  *
10562  * Removes clip area from @self.
10563  */
10564 void
10565 clutter_actor_remove_clip (ClutterActor *self)
10566 {
10567   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10568
10569   if (!self->priv->has_clip)
10570     return;
10571
10572   self->priv->has_clip = FALSE;
10573
10574   clutter_actor_queue_redraw (self);
10575
10576   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_CLIP]);
10577 }
10578
10579 /**
10580  * clutter_actor_has_clip:
10581  * @self: a #ClutterActor
10582  *
10583  * Determines whether the actor has a clip area set or not.
10584  *
10585  * Return value: %TRUE if the actor has a clip area set.
10586  *
10587  * Since: 0.1.1
10588  */
10589 gboolean
10590 clutter_actor_has_clip (ClutterActor *self)
10591 {
10592   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
10593
10594   return self->priv->has_clip;
10595 }
10596
10597 /**
10598  * clutter_actor_get_clip:
10599  * @self: a #ClutterActor
10600  * @xoff: (out) (allow-none): return location for the X offset of
10601  *   the clip rectangle, or %NULL
10602  * @yoff: (out) (allow-none): return location for the Y offset of
10603  *   the clip rectangle, or %NULL
10604  * @width: (out) (allow-none): return location for the width of
10605  *   the clip rectangle, or %NULL
10606  * @height: (out) (allow-none): return location for the height of
10607  *   the clip rectangle, or %NULL
10608  *
10609  * Gets the clip area for @self, if any is set
10610  *
10611  * Since: 0.6
10612  */
10613 void
10614 clutter_actor_get_clip (ClutterActor *self,
10615                         gfloat       *xoff,
10616                         gfloat       *yoff,
10617                         gfloat       *width,
10618                         gfloat       *height)
10619 {
10620   ClutterActorPrivate *priv;
10621
10622   g_return_if_fail (CLUTTER_IS_ACTOR (self));
10623
10624   priv = self->priv;
10625
10626   if (!priv->has_clip)
10627     return;
10628
10629   if (xoff != NULL)
10630     *xoff = priv->clip.x;
10631
10632   if (yoff != NULL)
10633     *yoff = priv->clip.y;
10634
10635   if (width != NULL)
10636     *width = priv->clip.width;
10637
10638   if (height != NULL)
10639     *height = priv->clip.height;
10640 }
10641
10642 /**
10643  * clutter_actor_get_children:
10644  * @self: a #ClutterActor
10645  *
10646  * Retrieves the list of children of @self.
10647  *
10648  * Return value: (transfer container) (element-type ClutterActor): A newly
10649  *   allocated #GList of #ClutterActor<!-- -->s. Use g_list_free() when
10650  *   done.
10651  *
10652  * Since: 1.10
10653  */
10654 GList *
10655 clutter_actor_get_children (ClutterActor *self)
10656 {
10657   ClutterActor *iter;
10658   GList *res;
10659
10660   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
10661
10662   /* we walk the list backward so that we can use prepend(),
10663    * which is O(1)
10664    */
10665   for (iter = self->priv->last_child, res = NULL;
10666        iter != NULL;
10667        iter = iter->priv->prev_sibling)
10668     {
10669       res = g_list_prepend (res, iter);
10670     }
10671
10672   return res;
10673 }
10674
10675 /*< private >
10676  * insert_child_at_depth:
10677  * @self: a #ClutterActor
10678  * @child: a #ClutterActor
10679  *
10680  * Inserts @child inside the list of children held by @self, using
10681  * the depth as the insertion criteria.
10682  *
10683  * This sadly makes the insertion not O(1), but we can keep the
10684  * list sorted so that the painters algorithm we use for painting
10685  * the children will work correctly.
10686  */
10687 static void
10688 insert_child_at_depth (ClutterActor *self,
10689                        ClutterActor *child,
10690                        gpointer      dummy G_GNUC_UNUSED)
10691 {
10692   ClutterActor *iter;
10693   float child_depth;
10694
10695   child->priv->parent = self;
10696
10697   child_depth =
10698     _clutter_actor_get_transform_info_or_defaults (child)->depth;
10699
10700   /* special-case the first child */
10701   if (self->priv->n_children == 0)
10702     {
10703       self->priv->first_child = child;
10704       self->priv->last_child = child;
10705
10706       child->priv->next_sibling = NULL;
10707       child->priv->prev_sibling = NULL;
10708
10709       return;
10710     }
10711
10712   /* Find the right place to insert the child so that it will still be
10713      sorted and the child will be after all of the actors at the same
10714      dept */
10715   for (iter = self->priv->first_child;
10716        iter != NULL;
10717        iter = iter->priv->next_sibling)
10718     {
10719       float iter_depth;
10720
10721       iter_depth =
10722         _clutter_actor_get_transform_info_or_defaults (iter)->depth;
10723
10724       if (iter_depth > child_depth)
10725         break;
10726     }
10727
10728   if (iter != NULL)
10729     {
10730       ClutterActor *tmp = iter->priv->prev_sibling;
10731
10732       if (tmp != NULL)
10733         tmp->priv->next_sibling = child;
10734
10735       /* Insert the node before the found one */
10736       child->priv->prev_sibling = iter->priv->prev_sibling;
10737       child->priv->next_sibling = iter;
10738       iter->priv->prev_sibling = child;
10739     }
10740   else
10741     {
10742       ClutterActor *tmp = self->priv->last_child;
10743
10744       if (tmp != NULL)
10745         tmp->priv->next_sibling = child;
10746
10747       /* insert the node at the end of the list */
10748       child->priv->prev_sibling = self->priv->last_child;
10749       child->priv->next_sibling = NULL;
10750     }
10751
10752   if (child->priv->prev_sibling == NULL)
10753     self->priv->first_child = child;
10754
10755   if (child->priv->next_sibling == NULL)
10756     self->priv->last_child = child;
10757 }
10758
10759 static void
10760 insert_child_at_index (ClutterActor *self,
10761                        ClutterActor *child,
10762                        gpointer      data_)
10763 {
10764   gint index_ = GPOINTER_TO_INT (data_);
10765
10766   child->priv->parent = self;
10767
10768   if (index_ == 0)
10769     {
10770       ClutterActor *tmp = self->priv->first_child;
10771
10772       if (tmp != NULL)
10773         tmp->priv->prev_sibling = child;
10774
10775       child->priv->prev_sibling = NULL;
10776       child->priv->next_sibling = tmp;
10777     }
10778   else if (index_ < 0 || index_ >= self->priv->n_children)
10779     {
10780       ClutterActor *tmp = self->priv->last_child;
10781
10782       if (tmp != NULL)
10783         tmp->priv->next_sibling = child;
10784
10785       child->priv->prev_sibling = tmp;
10786       child->priv->next_sibling = NULL;
10787     }
10788   else
10789     {
10790       ClutterActor *iter;
10791       int i;
10792
10793       for (iter = self->priv->first_child, i = 0;
10794            iter != NULL;
10795            iter = iter->priv->next_sibling, i += 1)
10796         {
10797           if (index_ == i)
10798             {
10799               ClutterActor *tmp = iter->priv->prev_sibling;
10800
10801               child->priv->prev_sibling = tmp;
10802               child->priv->next_sibling = iter;
10803
10804               iter->priv->prev_sibling = child;
10805
10806               if (tmp != NULL)
10807                 tmp->priv->next_sibling = child;
10808
10809               break;
10810             }
10811         }
10812     }
10813
10814   if (child->priv->prev_sibling == NULL)
10815     self->priv->first_child = child;
10816
10817   if (child->priv->next_sibling == NULL)
10818     self->priv->last_child = child;
10819 }
10820
10821 static void
10822 insert_child_above (ClutterActor *self,
10823                     ClutterActor *child,
10824                     gpointer      data)
10825 {
10826   ClutterActor *sibling = data;
10827
10828   child->priv->parent = self;
10829
10830   if (sibling == NULL)
10831     sibling = self->priv->last_child;
10832
10833   child->priv->prev_sibling = sibling;
10834
10835   if (sibling != NULL)
10836     {
10837       ClutterActor *tmp = sibling->priv->next_sibling;
10838
10839       child->priv->next_sibling = tmp;
10840
10841       if (tmp != NULL)
10842         tmp->priv->prev_sibling = child;
10843
10844       sibling->priv->next_sibling = child;
10845     }
10846   else
10847     child->priv->next_sibling = NULL;
10848
10849   if (child->priv->prev_sibling == NULL)
10850     self->priv->first_child = child;
10851
10852   if (child->priv->next_sibling == NULL)
10853     self->priv->last_child = child;
10854 }
10855
10856 static void
10857 insert_child_below (ClutterActor *self,
10858                     ClutterActor *child,
10859                     gpointer      data)
10860 {
10861   ClutterActor *sibling = data;
10862
10863   child->priv->parent = self;
10864
10865   if (sibling == NULL)
10866     sibling = self->priv->first_child;
10867
10868   child->priv->next_sibling = sibling;
10869
10870   if (sibling != NULL)
10871     {
10872       ClutterActor *tmp = sibling->priv->prev_sibling;
10873
10874       child->priv->prev_sibling = tmp;
10875
10876       if (tmp != NULL)
10877         tmp->priv->next_sibling = child;
10878
10879       sibling->priv->prev_sibling = child;
10880     }
10881   else
10882     child->priv->prev_sibling = NULL;
10883
10884   if (child->priv->prev_sibling == NULL)
10885     self->priv->first_child = child;
10886
10887   if (child->priv->next_sibling == NULL)
10888     self->priv->last_child = child;
10889 }
10890
10891 typedef void (* ClutterActorAddChildFunc) (ClutterActor *parent,
10892                                            ClutterActor *child,
10893                                            gpointer      data);
10894
10895 typedef enum {
10896   ADD_CHILD_CREATE_META       = 1 << 0,
10897   ADD_CHILD_EMIT_PARENT_SET   = 1 << 1,
10898   ADD_CHILD_EMIT_ACTOR_ADDED  = 1 << 2,
10899   ADD_CHILD_CHECK_STATE       = 1 << 3,
10900   ADD_CHILD_NOTIFY_FIRST_LAST = 1 << 4,
10901
10902   /* default flags for public API */
10903   ADD_CHILD_DEFAULT_FLAGS    = ADD_CHILD_CREATE_META |
10904                                ADD_CHILD_EMIT_PARENT_SET |
10905                                ADD_CHILD_EMIT_ACTOR_ADDED |
10906                                ADD_CHILD_CHECK_STATE |
10907                                ADD_CHILD_NOTIFY_FIRST_LAST,
10908
10909   /* flags for legacy/deprecated API */
10910   ADD_CHILD_LEGACY_FLAGS     = ADD_CHILD_EMIT_PARENT_SET |
10911                                ADD_CHILD_CHECK_STATE |
10912                                ADD_CHILD_NOTIFY_FIRST_LAST
10913 } ClutterActorAddChildFlags;
10914
10915 /*< private >
10916  * clutter_actor_add_child_internal:
10917  * @self: a #ClutterActor
10918  * @child: a #ClutterActor
10919  * @flags: control flags for actions
10920  * @add_func: delegate function
10921  * @data: (closure): data to pass to @add_func
10922  *
10923  * Adds @child to the list of children of @self.
10924  *
10925  * The actual insertion inside the list is delegated to @add_func: this
10926  * function will just set up the state, perform basic checks, and emit
10927  * signals.
10928  *
10929  * The @flags argument is used to perform additional operations.
10930  */
10931 static inline void
10932 clutter_actor_add_child_internal (ClutterActor              *self,
10933                                   ClutterActor              *child,
10934                                   ClutterActorAddChildFlags  flags,
10935                                   ClutterActorAddChildFunc   add_func,
10936                                   gpointer                   data)
10937 {
10938   ClutterTextDirection text_dir;
10939   gboolean create_meta;
10940   gboolean emit_parent_set, emit_actor_added;
10941   gboolean check_state;
10942   gboolean notify_first_last;
10943   ClutterActor *old_first_child, *old_last_child;
10944
10945   if (child->priv->parent != NULL)
10946     {
10947       g_warning ("The actor '%s' already has a parent, '%s'. You must "
10948                  "use clutter_actor_remove_child() first.",
10949                  _clutter_actor_get_debug_name (child),
10950                  _clutter_actor_get_debug_name (child->priv->parent));
10951       return;
10952     }
10953
10954   if (CLUTTER_ACTOR_IS_TOPLEVEL (child))
10955     {
10956       g_warning ("The actor '%s' is a top-level actor, and cannot be "
10957                  "a child of another actor.",
10958                  _clutter_actor_get_debug_name (child));
10959       return;
10960     }
10961
10962 #if 0
10963   /* XXX - this check disallows calling methods that change the stacking
10964    * order within the destruction sequence, by triggering a critical
10965    * warning first, and leaving the actor in an undefined state, which
10966    * then ends up being caught by an assertion.
10967    *
10968    * the reproducible sequence is:
10969    *
10970    *   - actor gets destroyed;
10971    *   - another actor, linked to the first, will try to change the
10972    *     stacking order of the first actor;
10973    *   - changing the stacking order is a composite operation composed
10974    *     by the following steps:
10975    *     1. ref() the child;
10976    *     2. remove_child_internal(), which removes the reference;
10977    *     3. add_child_internal(), which adds a reference;
10978    *   - the state of the actor is not changed between (2) and (3), as
10979    *     it could be an expensive recomputation;
10980    *   - if (3) bails out, then the actor is in an undefined state, but
10981    *     still alive;
10982    *   - the destruction sequence terminates, but the actor is unparented
10983    *     while its state indicates being parented instead.
10984    *   - assertion failure.
10985    *
10986    * the obvious fix would be to decompose each set_child_*_sibling()
10987    * method into proper remove_child()/add_child(), with state validation;
10988    * this may cause excessive work, though, and trigger a cascade of other
10989    * bugs in code that assumes that a change in the stacking order is an
10990    * atomic operation.
10991    *
10992    * another potential fix is to just remove this check here, and let
10993    * code doing stacking order changes inside the destruction sequence
10994    * of an actor continue doing the work.
10995    *
10996    * the third fix is to silently bail out early from every
10997    * set_child_*_sibling() and set_child_at_index() method, and avoid
10998    * doing work.
10999    *
11000    * I have a preference for the second solution, since it involves the
11001    * least amount of work, and the least amount of code duplication.
11002    *
11003    * see bug: https://bugzilla.gnome.org/show_bug.cgi?id=670647
11004    */
11005   if (CLUTTER_ACTOR_IN_DESTRUCTION (child))
11006     {
11007       g_warning ("The actor '%s' is currently being destroyed, and "
11008                  "cannot be added as a child of another actor.",
11009                  _clutter_actor_get_debug_name (child));
11010       return;
11011     }
11012 #endif
11013
11014   create_meta = (flags & ADD_CHILD_CREATE_META) != 0;
11015   emit_parent_set = (flags & ADD_CHILD_EMIT_PARENT_SET) != 0;
11016   emit_actor_added = (flags & ADD_CHILD_EMIT_ACTOR_ADDED) != 0;
11017   check_state = (flags & ADD_CHILD_CHECK_STATE) != 0;
11018   notify_first_last = (flags & ADD_CHILD_NOTIFY_FIRST_LAST) != 0;
11019
11020   old_first_child = self->priv->first_child;
11021   old_last_child = self->priv->last_child;
11022
11023   g_object_freeze_notify (G_OBJECT (self));
11024
11025   if (create_meta)
11026     clutter_container_create_child_meta (CLUTTER_CONTAINER (self), child);
11027
11028   g_object_ref_sink (child);
11029   child->priv->parent = NULL;
11030   child->priv->next_sibling = NULL;
11031   child->priv->prev_sibling = NULL;
11032
11033   /* delegate the actual insertion */
11034   add_func (self, child, data);
11035
11036   g_assert (child->priv->parent == self);
11037
11038   self->priv->n_children += 1;
11039
11040   self->priv->age += 1;
11041
11042   /* if push_internal() has been called then we automatically set
11043    * the flag on the actor
11044    */
11045   if (self->priv->internal_child)
11046     CLUTTER_SET_PRIVATE_FLAGS (child, CLUTTER_INTERNAL_CHILD);
11047
11048   /* clutter_actor_reparent() will emit ::parent-set for us */
11049   if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
11050     g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
11051
11052   if (check_state)
11053     {
11054       /* If parent is mapped or realized, we need to also be mapped or
11055        * realized once we're inside the parent.
11056        */
11057       clutter_actor_update_map_state (child, MAP_STATE_CHECK);
11058
11059       /* propagate the parent's text direction to the child */
11060       text_dir = clutter_actor_get_text_direction (self);
11061       clutter_actor_set_text_direction (child, text_dir);
11062     }
11063
11064   if (child->priv->show_on_set_parent)
11065     clutter_actor_show (child);
11066
11067   if (CLUTTER_ACTOR_IS_MAPPED (child))
11068     clutter_actor_queue_redraw (child);
11069
11070   /* maintain the invariant that if an actor needs layout,
11071    * its parents do as well
11072    */
11073   if (child->priv->needs_width_request ||
11074       child->priv->needs_height_request ||
11075       child->priv->needs_allocation)
11076     {
11077       /* we work around the short-circuiting we do
11078        * in clutter_actor_queue_relayout() since we
11079        * want to force a relayout
11080        */
11081       child->priv->needs_width_request = TRUE;
11082       child->priv->needs_height_request = TRUE;
11083       child->priv->needs_allocation = TRUE;
11084
11085       clutter_actor_queue_relayout (child->priv->parent);
11086     }
11087
11088   if (emit_actor_added)
11089     g_signal_emit_by_name (self, "actor-added", child);
11090
11091   if (notify_first_last)
11092     {
11093       if (old_first_child != self->priv->first_child)
11094         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FIRST_CHILD]);
11095
11096       if (old_last_child != self->priv->last_child)
11097         g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LAST_CHILD]);
11098     }
11099
11100   g_object_thaw_notify (G_OBJECT (self));
11101 }
11102
11103 /**
11104  * clutter_actor_add_child:
11105  * @self: a #ClutterActor
11106  * @child: a #ClutterActor
11107  *
11108  * Adds @child to the children of @self.
11109  *
11110  * This function will acquire a reference on @child that will only
11111  * be released when calling clutter_actor_remove_child().
11112  *
11113  * This function will take into consideration the #ClutterActor:depth
11114  * of @child, and will keep the list of children sorted.
11115  *
11116  * This function will emit the #ClutterContainer::actor-added signal
11117  * on @self.
11118  *
11119  * Since: 1.10
11120  */
11121 void
11122 clutter_actor_add_child (ClutterActor *self,
11123                          ClutterActor *child)
11124 {
11125   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11126   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11127   g_return_if_fail (self != child);
11128   g_return_if_fail (child->priv->parent == NULL);
11129
11130   clutter_actor_add_child_internal (self, child,
11131                                     ADD_CHILD_DEFAULT_FLAGS,
11132                                     insert_child_at_depth,
11133                                     NULL);
11134 }
11135
11136 /**
11137  * clutter_actor_insert_child_at_index:
11138  * @self: a #ClutterActor
11139  * @child: a #ClutterActor
11140  * @index_: the index
11141  *
11142  * Inserts @child into the list of children of @self, using the
11143  * given @index_. If @index_ is greater than the number of children
11144  * in @self, or is less than 0, then the new child is added at the end.
11145  *
11146  * This function will acquire a reference on @child that will only
11147  * be released when calling clutter_actor_remove_child().
11148  *
11149  * This function will not take into consideration the #ClutterActor:depth
11150  * of @child.
11151  *
11152  * This function will emit the #ClutterContainer::actor-added signal
11153  * on @self.
11154  *
11155  * Since: 1.10
11156  */
11157 void
11158 clutter_actor_insert_child_at_index (ClutterActor *self,
11159                                      ClutterActor *child,
11160                                      gint          index_)
11161 {
11162   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11163   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11164   g_return_if_fail (self != child);
11165   g_return_if_fail (child->priv->parent == NULL);
11166
11167   clutter_actor_add_child_internal (self, child,
11168                                     ADD_CHILD_DEFAULT_FLAGS,
11169                                     insert_child_at_index,
11170                                     GINT_TO_POINTER (index_));
11171 }
11172
11173 /**
11174  * clutter_actor_insert_child_above:
11175  * @self: a #ClutterActor
11176  * @child: a #ClutterActor
11177  * @sibling: (allow-none): a child of @self, or %NULL
11178  *
11179  * Inserts @child into the list of children of @self, above another
11180  * child of @self or, if @sibling is %NULL, above all the children
11181  * of @self.
11182  *
11183  * This function will acquire a reference on @child that will only
11184  * be released when calling clutter_actor_remove_child().
11185  *
11186  * This function will not take into consideration the #ClutterActor:depth
11187  * of @child.
11188  *
11189  * This function will emit the #ClutterContainer::actor-added signal
11190  * on @self.
11191  *
11192  * Since: 1.10
11193  */
11194 void
11195 clutter_actor_insert_child_above (ClutterActor *self,
11196                                   ClutterActor *child,
11197                                   ClutterActor *sibling)
11198 {
11199   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11200   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11201   g_return_if_fail (self != child);
11202   g_return_if_fail (child != sibling);
11203   g_return_if_fail (child->priv->parent == NULL);
11204   g_return_if_fail (sibling == NULL ||
11205                     (CLUTTER_IS_ACTOR (sibling) &&
11206                      sibling->priv->parent == self));
11207
11208   clutter_actor_add_child_internal (self, child,
11209                                     ADD_CHILD_DEFAULT_FLAGS,
11210                                     insert_child_above,
11211                                     sibling);
11212 }
11213
11214 /**
11215  * clutter_actor_insert_child_below:
11216  * @self: a #ClutterActor
11217  * @child: a #ClutterActor
11218  * @sibling: (allow-none): a child of @self, or %NULL
11219  *
11220  * Inserts @child into the list of children of @self, below another
11221  * child of @self or, if @sibling is %NULL, below all the children
11222  * of @self.
11223  *
11224  * This function will acquire a reference on @child that will only
11225  * be released when calling clutter_actor_remove_child().
11226  *
11227  * This function will not take into consideration the #ClutterActor:depth
11228  * of @child.
11229  *
11230  * This function will emit the #ClutterContainer::actor-added signal
11231  * on @self.
11232  *
11233  * Since: 1.10
11234  */
11235 void
11236 clutter_actor_insert_child_below (ClutterActor *self,
11237                                   ClutterActor *child,
11238                                   ClutterActor *sibling)
11239 {
11240   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11241   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11242   g_return_if_fail (self != child);
11243   g_return_if_fail (child != sibling);
11244   g_return_if_fail (child->priv->parent == NULL);
11245   g_return_if_fail (sibling == NULL ||
11246                     (CLUTTER_IS_ACTOR (sibling) &&
11247                      sibling->priv->parent == self));
11248
11249   clutter_actor_add_child_internal (self, child,
11250                                     ADD_CHILD_DEFAULT_FLAGS,
11251                                     insert_child_below,
11252                                     sibling);
11253 }
11254
11255 /**
11256  * clutter_actor_set_parent:
11257  * @self: A #ClutterActor
11258  * @parent: A new #ClutterActor parent
11259  *
11260  * Sets the parent of @self to @parent.
11261  *
11262  * This function will result in @parent acquiring a reference on @self,
11263  * eventually by sinking its floating reference first. The reference
11264  * will be released by clutter_actor_unparent().
11265  *
11266  * This function should only be called by legacy #ClutterActor<!-- -->s
11267  * implementing the #ClutterContainer interface.
11268  *
11269  * Deprecated: 1.10: Use clutter_actor_add_child() instead.
11270  */
11271 void
11272 clutter_actor_set_parent (ClutterActor *self,
11273                           ClutterActor *parent)
11274 {
11275   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11276   g_return_if_fail (CLUTTER_IS_ACTOR (parent));
11277   g_return_if_fail (self != parent);
11278   g_return_if_fail (self->priv->parent == NULL);
11279
11280   /* as this function will be called inside ClutterContainer::add
11281    * implementations or when building up a composite actor, we have
11282    * to preserve the old behaviour, and not create child meta or
11283    * emit the ::actor-added signal, to avoid recursion or double
11284    * emissions
11285    */
11286   clutter_actor_add_child_internal (parent, self,
11287                                     ADD_CHILD_LEGACY_FLAGS,
11288                                     insert_child_at_depth,
11289                                     NULL);
11290 }
11291
11292 /**
11293  * clutter_actor_get_parent:
11294  * @self: A #ClutterActor
11295  *
11296  * Retrieves the parent of @self.
11297  *
11298  * Return Value: (transfer none): The #ClutterActor parent, or %NULL
11299  *  if no parent is set
11300  */
11301 ClutterActor *
11302 clutter_actor_get_parent (ClutterActor *self)
11303 {
11304   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
11305
11306   return self->priv->parent;
11307 }
11308
11309 /**
11310  * clutter_actor_get_paint_visibility:
11311  * @self: A #ClutterActor
11312  *
11313  * Retrieves the 'paint' visibility of an actor recursively checking for non
11314  * visible parents.
11315  *
11316  * This is by definition the same as %CLUTTER_ACTOR_IS_MAPPED.
11317  *
11318  * Return Value: %TRUE if the actor is visibile and will be painted.
11319  *
11320  * Since: 0.8.4
11321  */
11322 gboolean
11323 clutter_actor_get_paint_visibility (ClutterActor *actor)
11324 {
11325   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11326
11327   return CLUTTER_ACTOR_IS_MAPPED (actor);
11328 }
11329
11330 /**
11331  * clutter_actor_remove_child:
11332  * @self: a #ClutterActor
11333  * @child: a #ClutterActor
11334  *
11335  * Removes @child from the children of @self.
11336  *
11337  * This function will release the reference added by
11338  * clutter_actor_add_child(), so if you want to keep using @child
11339  * you will have to acquire a referenced on it before calling this
11340  * function.
11341  *
11342  * This function will emit the #ClutterContainer::actor-removed
11343  * signal on @self.
11344  *
11345  * Since: 1.10
11346  */
11347 void
11348 clutter_actor_remove_child (ClutterActor *self,
11349                             ClutterActor *child)
11350 {
11351   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11352   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11353   g_return_if_fail (self != child);
11354   g_return_if_fail (child->priv->parent != NULL);
11355   g_return_if_fail (child->priv->parent == self);
11356
11357   clutter_actor_remove_child_internal (self, child,
11358                                        REMOVE_CHILD_DEFAULT_FLAGS);
11359 }
11360
11361 /**
11362  * clutter_actor_remove_all_children:
11363  * @self: a #ClutterActor
11364  *
11365  * Removes all children of @self.
11366  *
11367  * This function releases the reference added by inserting a child actor
11368  * in the list of children of @self.
11369  *
11370  * If the reference count of a child drops to zero, the child will be
11371  * destroyed. If you want to ensure the destruction of all the children
11372  * of @self, use clutter_actor_destroy_all_children().
11373  *
11374  * Since: 1.10
11375  */
11376 void
11377 clutter_actor_remove_all_children (ClutterActor *self)
11378 {
11379   ClutterActorIter iter;
11380
11381   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11382
11383   if (self->priv->n_children == 0)
11384     return;
11385
11386   g_object_freeze_notify (G_OBJECT (self));
11387
11388   clutter_actor_iter_init (&iter, self);
11389   while (clutter_actor_iter_next (&iter, NULL))
11390     clutter_actor_iter_remove (&iter);
11391
11392   g_object_thaw_notify (G_OBJECT (self));
11393
11394   /* sanity check */
11395   g_assert (self->priv->first_child == NULL);
11396   g_assert (self->priv->last_child == NULL);
11397   g_assert (self->priv->n_children == 0);
11398 }
11399
11400 /**
11401  * clutter_actor_destroy_all_children:
11402  * @self: a #ClutterActor
11403  *
11404  * Destroys all children of @self.
11405  *
11406  * This function releases the reference added by inserting a child
11407  * actor in the list of children of @self, and ensures that the
11408  * #ClutterActor::destroy signal is emitted on each child of the
11409  * actor.
11410  *
11411  * By default, #ClutterActor will emit the #ClutterActor::destroy signal
11412  * when its reference count drops to 0; the default handler of the
11413  * #ClutterActor::destroy signal will destroy all the children of an
11414  * actor. This function ensures that all children are destroyed, instead
11415  * of just removed from @self, unlike clutter_actor_remove_all_children()
11416  * which will merely release the reference and remove each child.
11417  *
11418  * Unless you acquired an additional reference on each child of @self
11419  * prior to calling clutter_actor_remove_all_children() and want to reuse
11420  * the actors, you should use clutter_actor_destroy_all_children() in
11421  * order to make sure that children are destroyed and signal handlers
11422  * are disconnected even in cases where circular references prevent this
11423  * from automatically happening through reference counting alone.
11424  *
11425  * Since: 1.10
11426  */
11427 void
11428 clutter_actor_destroy_all_children (ClutterActor *self)
11429 {
11430   ClutterActorIter iter;
11431
11432   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11433
11434   if (self->priv->n_children == 0)
11435     return;
11436
11437   g_object_freeze_notify (G_OBJECT (self));
11438
11439   clutter_actor_iter_init (&iter, self);
11440   while (clutter_actor_iter_next (&iter, NULL))
11441     clutter_actor_iter_destroy (&iter);
11442
11443   g_object_thaw_notify (G_OBJECT (self));
11444
11445   /* sanity check */
11446   g_assert (self->priv->first_child == NULL);
11447   g_assert (self->priv->last_child == NULL);
11448   g_assert (self->priv->n_children == 0);
11449 }
11450
11451 typedef struct _InsertBetweenData {
11452   ClutterActor *prev_sibling;
11453   ClutterActor *next_sibling;
11454 } InsertBetweenData;
11455
11456 static void
11457 insert_child_between (ClutterActor *self,
11458                       ClutterActor *child,
11459                       gpointer      data_)
11460 {
11461   InsertBetweenData *data = data_;
11462   ClutterActor *prev_sibling = data->prev_sibling;
11463   ClutterActor *next_sibling = data->next_sibling;
11464
11465   child->priv->parent = self;
11466   child->priv->prev_sibling = prev_sibling;
11467   child->priv->next_sibling = next_sibling;
11468
11469   if (prev_sibling != NULL)
11470     prev_sibling->priv->next_sibling = child;
11471
11472   if (next_sibling != NULL)
11473     next_sibling->priv->prev_sibling = child;
11474
11475   if (child->priv->prev_sibling == NULL)
11476     self->priv->first_child = child;
11477
11478   if (child->priv->next_sibling == NULL)
11479     self->priv->last_child = child;
11480 }
11481
11482 /**
11483  * clutter_actor_replace_child:
11484  * @self: a #ClutterActor
11485  * @old_child: the child of @self to replace
11486  * @new_child: the #ClutterActor to replace @old_child
11487  *
11488  * Replaces @old_child with @new_child in the list of children of @self.
11489  *
11490  * Since: 1.10
11491  */
11492 void
11493 clutter_actor_replace_child (ClutterActor *self,
11494                              ClutterActor *old_child,
11495                              ClutterActor *new_child)
11496 {
11497   ClutterActor *prev_sibling, *next_sibling;
11498   InsertBetweenData clos;
11499
11500   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11501   g_return_if_fail (CLUTTER_IS_ACTOR (old_child));
11502   g_return_if_fail (old_child->priv->parent == self);
11503   g_return_if_fail (CLUTTER_IS_ACTOR (new_child));
11504   g_return_if_fail (old_child != new_child);
11505   g_return_if_fail (new_child != self);
11506   g_return_if_fail (new_child->priv->parent == NULL);
11507
11508   prev_sibling = old_child->priv->prev_sibling;
11509   next_sibling = old_child->priv->next_sibling;
11510   clutter_actor_remove_child_internal (self, old_child,
11511                                        REMOVE_CHILD_DEFAULT_FLAGS);
11512
11513   clos.prev_sibling = prev_sibling;
11514   clos.next_sibling = next_sibling;
11515   clutter_actor_add_child_internal (self, new_child,
11516                                     ADD_CHILD_DEFAULT_FLAGS,
11517                                     insert_child_between,
11518                                     &clos);
11519 }
11520
11521 /**
11522  * clutter_actor_unparent:
11523  * @self: a #ClutterActor
11524  *
11525  * Removes the parent of @self.
11526  *
11527  * This will cause the parent of @self to release the reference
11528  * acquired when calling clutter_actor_set_parent(), so if you
11529  * want to keep @self you will have to acquire a reference of
11530  * your own, through g_object_ref().
11531  *
11532  * This function should only be called by legacy #ClutterActor<!-- -->s
11533  * implementing the #ClutterContainer interface.
11534  *
11535  * Since: 0.1.1
11536  *
11537  * Deprecated: 1.10: Use clutter_actor_remove_child() instead.
11538  */
11539 void
11540 clutter_actor_unparent (ClutterActor *self)
11541 {
11542   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11543
11544   if (self->priv->parent == NULL)
11545     return;
11546
11547   clutter_actor_remove_child_internal (self->priv->parent, self,
11548                                        REMOVE_CHILD_LEGACY_FLAGS);
11549 }
11550
11551 /**
11552  * clutter_actor_reparent:
11553  * @self: a #ClutterActor
11554  * @new_parent: the new #ClutterActor parent
11555  *
11556  * Resets the parent actor of @self.
11557  *
11558  * This function is logically equivalent to calling clutter_actor_unparent()
11559  * and clutter_actor_set_parent(), but more efficiently implemented, as it
11560  * ensures the child is not finalized when unparented, and emits the
11561  * #ClutterActor::parent-set signal only once.
11562  *
11563  * In reality, calling this function is less useful than it sounds, as some
11564  * application code may rely on changes in the intermediate state between
11565  * removal and addition of the actor from its old parent to the @new_parent.
11566  * Thus, it is strongly encouraged to avoid using this function in application
11567  * code.
11568  *
11569  * Since: 0.2
11570  *
11571  * Deprecated: 1.10: Use clutter_actor_remove_child() and
11572  *   clutter_actor_add_child() instead; remember to take a reference on
11573  *   the actor being removed before calling clutter_actor_remove_child()
11574  *   to avoid the reference count dropping to zero and the actor being
11575  *   destroyed.
11576  */
11577 void
11578 clutter_actor_reparent (ClutterActor *self,
11579                         ClutterActor *new_parent)
11580 {
11581   ClutterActorPrivate *priv;
11582
11583   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11584   g_return_if_fail (CLUTTER_IS_ACTOR (new_parent));
11585   g_return_if_fail (self != new_parent);
11586
11587   if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
11588     {
11589       g_warning ("Cannot set a parent on a toplevel actor");
11590       return;
11591     }
11592
11593   if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
11594     {
11595       g_warning ("Cannot set a parent currently being destroyed");
11596       return;
11597     }
11598
11599   priv = self->priv;
11600
11601   if (priv->parent != new_parent)
11602     {
11603       ClutterActor *old_parent;
11604
11605       CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11606
11607       old_parent = priv->parent;
11608
11609       g_object_ref (self);
11610
11611       if (old_parent != NULL)
11612         {
11613          /* go through the Container implementation if this is a regular
11614           * child and not an internal one
11615           */
11616          if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11617            {
11618              ClutterContainer *parent = CLUTTER_CONTAINER (old_parent);
11619
11620              /* this will have to call unparent() */
11621              clutter_container_remove_actor (parent, self);
11622            }
11623          else
11624            clutter_actor_remove_child_internal (old_parent, self,
11625                                                 REMOVE_CHILD_LEGACY_FLAGS);
11626         }
11627
11628       /* Note, will call set_parent() */
11629       if (!CLUTTER_ACTOR_IS_INTERNAL_CHILD (self))
11630         clutter_container_add_actor (CLUTTER_CONTAINER (new_parent), self);
11631       else
11632         clutter_actor_add_child_internal (new_parent, self,
11633                                           ADD_CHILD_LEGACY_FLAGS,
11634                                           insert_child_at_depth,
11635                                           NULL);
11636
11637       /* we emit the ::parent-set signal once */
11638       g_signal_emit (self, actor_signals[PARENT_SET], 0, old_parent);
11639
11640       CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_REPARENT);
11641
11642       /* the IN_REPARENT flag suspends state updates */
11643       clutter_actor_update_map_state (self, MAP_STATE_CHECK);
11644
11645       g_object_unref (self);
11646    }
11647 }
11648
11649 /**
11650  * clutter_actor_contains:
11651  * @self: A #ClutterActor
11652  * @descendant: A #ClutterActor, possibly contained in @self
11653  *
11654  * Determines if @descendant is contained inside @self (either as an
11655  * immediate child, or as a deeper descendant). If @self and
11656  * @descendant point to the same actor then it will also return %TRUE.
11657  *
11658  * Return value: whether @descendent is contained within @self
11659  *
11660  * Since: 1.4
11661  */
11662 gboolean
11663 clutter_actor_contains (ClutterActor *self,
11664                         ClutterActor *descendant)
11665 {
11666   ClutterActor *actor;
11667
11668   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
11669   g_return_val_if_fail (CLUTTER_IS_ACTOR (descendant), FALSE);
11670
11671   for (actor = descendant; actor; actor = actor->priv->parent)
11672     if (actor == self)
11673       return TRUE;
11674
11675   return FALSE;
11676 }
11677
11678 /**
11679  * clutter_actor_set_child_above_sibling:
11680  * @self: a #ClutterActor
11681  * @child: a #ClutterActor child of @self
11682  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11683  *
11684  * Sets @child to be above @sibling in the list of children of @self.
11685  *
11686  * If @sibling is %NULL, @child will be the new last child of @self.
11687  *
11688  * This function is logically equivalent to removing @child and using
11689  * clutter_actor_insert_child_above(), but it will not emit signals
11690  * or change state on @child.
11691  *
11692  * Since: 1.10
11693  */
11694 void
11695 clutter_actor_set_child_above_sibling (ClutterActor *self,
11696                                        ClutterActor *child,
11697                                        ClutterActor *sibling)
11698 {
11699   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11700   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11701   g_return_if_fail (child->priv->parent == self);
11702   g_return_if_fail (child != sibling);
11703   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11704
11705   if (sibling != NULL)
11706     g_return_if_fail (sibling->priv->parent == self);
11707
11708   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11709       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11710       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11711     return;
11712
11713   /* we don't want to change the state of child, or emit signals, or
11714    * regenerate ChildMeta instances here, but we still want to follow
11715    * the correct sequence of steps encoded in remove_child() and
11716    * add_child(), so that correctness is ensured, and we only go
11717    * through one known code path.
11718    */
11719   g_object_ref (child);
11720   clutter_actor_remove_child_internal (self, child, 0);
11721   clutter_actor_add_child_internal (self, child,
11722                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11723                                     insert_child_above,
11724                                     sibling);
11725
11726   clutter_actor_queue_relayout (self);
11727 }
11728
11729 /**
11730  * clutter_actor_set_child_below_sibling:
11731  * @self: a #ClutterActor
11732  * @child: a #ClutterActor child of @self
11733  * @sibling: (allow-none): a #ClutterActor child of @self, or %NULL
11734  *
11735  * Sets @child to be below @sibling in the list of children of @self.
11736  *
11737  * If @sibling is %NULL, @child will be the new first child of @self.
11738  *
11739  * This function is logically equivalent to removing @self and using
11740  * clutter_actor_insert_child_below(), but it will not emit signals
11741  * or change state on @child.
11742  *
11743  * Since: 1.10
11744  */
11745 void
11746 clutter_actor_set_child_below_sibling (ClutterActor *self,
11747                                        ClutterActor *child,
11748                                        ClutterActor *sibling)
11749 {
11750   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11751   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11752   g_return_if_fail (child->priv->parent == self);
11753   g_return_if_fail (child != sibling);
11754   g_return_if_fail (sibling == NULL || CLUTTER_IS_ACTOR (sibling));
11755
11756   if (sibling != NULL)
11757     g_return_if_fail (sibling->priv->parent == self);
11758
11759   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11760       CLUTTER_ACTOR_IN_DESTRUCTION (child) ||
11761       (sibling != NULL && CLUTTER_ACTOR_IN_DESTRUCTION (sibling)))
11762     return;
11763
11764   /* see the comment in set_child_above_sibling() */
11765   g_object_ref (child);
11766   clutter_actor_remove_child_internal (self, child, 0);
11767   clutter_actor_add_child_internal (self, child,
11768                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11769                                     insert_child_below,
11770                                     sibling);
11771
11772   clutter_actor_queue_relayout (self);
11773 }
11774
11775 /**
11776  * clutter_actor_set_child_at_index:
11777  * @self: a #ClutterActor
11778  * @child: a #ClutterActor child of @self
11779  * @index_: the new index for @child
11780  *
11781  * Changes the index of @child in the list of children of @self.
11782  *
11783  * This function is logically equivalent to removing @child and
11784  * calling clutter_actor_insert_child_at_index(), but it will not
11785  * emit signals or change state on @child.
11786  *
11787  * Since: 1.10
11788  */
11789 void
11790 clutter_actor_set_child_at_index (ClutterActor *self,
11791                                   ClutterActor *child,
11792                                   gint          index_)
11793 {
11794   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11795   g_return_if_fail (CLUTTER_IS_ACTOR (child));
11796   g_return_if_fail (child->priv->parent == self);
11797   g_return_if_fail (index_ <= self->priv->n_children);
11798
11799   if (CLUTTER_ACTOR_IN_DESTRUCTION (self) ||
11800       CLUTTER_ACTOR_IN_DESTRUCTION (child))
11801     return;
11802
11803   g_object_ref (child);
11804   clutter_actor_remove_child_internal (self, child, 0);
11805   clutter_actor_add_child_internal (self, child,
11806                                     ADD_CHILD_NOTIFY_FIRST_LAST,
11807                                     insert_child_at_index,
11808                                     GINT_TO_POINTER (index_));
11809
11810   clutter_actor_queue_relayout (self);
11811 }
11812
11813 /**
11814  * clutter_actor_raise:
11815  * @self: A #ClutterActor
11816  * @below: (allow-none): A #ClutterActor to raise above.
11817  *
11818  * Puts @self above @below.
11819  *
11820  * Both actors must have the same parent, and the parent must implement
11821  * the #ClutterContainer interface
11822  *
11823  * This function calls clutter_container_raise_child() internally.
11824  *
11825  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() instead.
11826  */
11827 void
11828 clutter_actor_raise (ClutterActor *self,
11829                      ClutterActor *below)
11830 {
11831   ClutterActor *parent;
11832
11833   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11834
11835   parent = clutter_actor_get_parent (self);
11836   if (parent == NULL)
11837     {
11838       g_warning ("%s: Actor '%s' is not inside a container",
11839                  G_STRFUNC,
11840                  _clutter_actor_get_debug_name (self));
11841       return;
11842     }
11843
11844   if (below != NULL)
11845     {
11846       if (parent != clutter_actor_get_parent (below))
11847         {
11848           g_warning ("%s Actor '%s' is not in the same container as "
11849                      "actor '%s'",
11850                      G_STRFUNC,
11851                      _clutter_actor_get_debug_name (self),
11852                      _clutter_actor_get_debug_name (below));
11853           return;
11854         }
11855     }
11856
11857   clutter_container_raise_child (CLUTTER_CONTAINER (parent), self, below);
11858 }
11859
11860 /**
11861  * clutter_actor_lower:
11862  * @self: A #ClutterActor
11863  * @above: (allow-none): A #ClutterActor to lower below
11864  *
11865  * Puts @self below @above.
11866  *
11867  * Both actors must have the same parent, and the parent must implement
11868  * the #ClutterContainer interface.
11869  *
11870  * This function calls clutter_container_lower_child() internally.
11871  *
11872  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() instead.
11873  */
11874 void
11875 clutter_actor_lower (ClutterActor *self,
11876                      ClutterActor *above)
11877 {
11878   ClutterActor *parent;
11879
11880   g_return_if_fail (CLUTTER_IS_ACTOR (self));
11881
11882   parent = clutter_actor_get_parent (self);
11883   if (parent == NULL)
11884     {
11885       g_warning ("%s: Actor of type %s is not inside a container",
11886                  G_STRFUNC,
11887                  _clutter_actor_get_debug_name (self));
11888       return;
11889     }
11890
11891   if (above)
11892     {
11893       if (parent != clutter_actor_get_parent (above))
11894         {
11895           g_warning ("%s: Actor '%s' is not in the same container as "
11896                      "actor '%s'",
11897                      G_STRFUNC,
11898                      _clutter_actor_get_debug_name (self),
11899                      _clutter_actor_get_debug_name (above));
11900           return;
11901         }
11902     }
11903
11904   clutter_container_lower_child (CLUTTER_CONTAINER (parent), self, above);
11905 }
11906
11907 /**
11908  * clutter_actor_raise_top:
11909  * @self: A #ClutterActor
11910  *
11911  * Raises @self to the top.
11912  *
11913  * This function calls clutter_actor_raise() internally.
11914  *
11915  * Deprecated: 1.10: Use clutter_actor_set_child_above_sibling() with
11916  *   a %NULL sibling, instead.
11917  */
11918 void
11919 clutter_actor_raise_top (ClutterActor *self)
11920 {
11921   clutter_actor_raise (self, NULL);
11922 }
11923
11924 /**
11925  * clutter_actor_lower_bottom:
11926  * @self: A #ClutterActor
11927  *
11928  * Lowers @self to the bottom.
11929  *
11930  * This function calls clutter_actor_lower() internally.
11931  *
11932  * Deprecated: 1.10: Use clutter_actor_set_child_below_sibling() with
11933  *   a %NULL sibling, instead.
11934  */
11935 void
11936 clutter_actor_lower_bottom (ClutterActor *self)
11937 {
11938   clutter_actor_lower (self, NULL);
11939 }
11940
11941 /*
11942  * Event handling
11943  */
11944
11945 /**
11946  * clutter_actor_event:
11947  * @actor: a #ClutterActor
11948  * @event: a #ClutterEvent
11949  * @capture: TRUE if event in in capture phase, FALSE otherwise.
11950  *
11951  * This function is used to emit an event on the main stage.
11952  * You should rarely need to use this function, except for
11953  * synthetising events.
11954  *
11955  * Return value: the return value from the signal emission: %TRUE
11956  *   if the actor handled the event, or %FALSE if the event was
11957  *   not handled
11958  *
11959  * Since: 0.6
11960  */
11961 gboolean
11962 clutter_actor_event (ClutterActor *actor,
11963                      ClutterEvent *event,
11964                      gboolean      capture)
11965 {
11966   gboolean retval = FALSE;
11967   gint signal_num = -1;
11968
11969   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
11970   g_return_val_if_fail (event != NULL, FALSE);
11971
11972   g_object_ref (actor);
11973
11974   if (capture)
11975     {
11976       g_signal_emit (actor, actor_signals[CAPTURED_EVENT], 0,
11977                      event,
11978                      &retval);
11979       goto out;
11980     }
11981
11982   g_signal_emit (actor, actor_signals[EVENT], 0, event, &retval);
11983
11984   if (!retval)
11985     {
11986       switch (event->type)
11987         {
11988         case CLUTTER_NOTHING:
11989           break;
11990         case CLUTTER_BUTTON_PRESS:
11991           signal_num = BUTTON_PRESS_EVENT;
11992           break;
11993         case CLUTTER_BUTTON_RELEASE:
11994           signal_num = BUTTON_RELEASE_EVENT;
11995           break;
11996         case CLUTTER_SCROLL:
11997           signal_num = SCROLL_EVENT;
11998           break;
11999         case CLUTTER_KEY_PRESS:
12000           signal_num = KEY_PRESS_EVENT;
12001           break;
12002         case CLUTTER_KEY_RELEASE:
12003           signal_num = KEY_RELEASE_EVENT;
12004           break;
12005         case CLUTTER_MOTION:
12006           signal_num = MOTION_EVENT;
12007           break;
12008         case CLUTTER_ENTER:
12009           signal_num = ENTER_EVENT;
12010           break;
12011         case CLUTTER_LEAVE:
12012           signal_num = LEAVE_EVENT;
12013           break;
12014         case CLUTTER_DELETE:
12015         case CLUTTER_DESTROY_NOTIFY:
12016         case CLUTTER_CLIENT_MESSAGE:
12017         default:
12018           signal_num = -1;
12019           break;
12020         }
12021
12022       if (signal_num != -1)
12023         g_signal_emit (actor, actor_signals[signal_num], 0,
12024                        event, &retval);
12025     }
12026
12027 out:
12028   g_object_unref (actor);
12029
12030   return retval;
12031 }
12032
12033 /**
12034  * clutter_actor_set_reactive:
12035  * @actor: a #ClutterActor
12036  * @reactive: whether the actor should be reactive to events
12037  *
12038  * Sets @actor as reactive. Reactive actors will receive events.
12039  *
12040  * Since: 0.6
12041  */
12042 void
12043 clutter_actor_set_reactive (ClutterActor *actor,
12044                             gboolean      reactive)
12045 {
12046   g_return_if_fail (CLUTTER_IS_ACTOR (actor));
12047
12048   if (reactive == CLUTTER_ACTOR_IS_REACTIVE (actor))
12049     return;
12050
12051   if (reactive)
12052     CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12053   else
12054     CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REACTIVE);
12055
12056   g_object_notify_by_pspec (G_OBJECT (actor), obj_props[PROP_REACTIVE]);
12057 }
12058
12059 /**
12060  * clutter_actor_get_reactive:
12061  * @actor: a #ClutterActor
12062  *
12063  * Checks whether @actor is marked as reactive.
12064  *
12065  * Return value: %TRUE if the actor is reactive
12066  *
12067  * Since: 0.6
12068  */
12069 gboolean
12070 clutter_actor_get_reactive (ClutterActor *actor)
12071 {
12072   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), FALSE);
12073
12074   return CLUTTER_ACTOR_IS_REACTIVE (actor) ? TRUE : FALSE;
12075 }
12076
12077 /**
12078  * clutter_actor_get_anchor_point:
12079  * @self: a #ClutterActor
12080  * @anchor_x: (out): return location for the X coordinate of the anchor point
12081  * @anchor_y: (out): return location for the Y coordinate of the anchor point
12082  *
12083  * Gets the current anchor point of the @actor in pixels.
12084  *
12085  * Since: 0.6
12086  */
12087 void
12088 clutter_actor_get_anchor_point (ClutterActor *self,
12089                                 gfloat       *anchor_x,
12090                                 gfloat       *anchor_y)
12091 {
12092   const ClutterTransformInfo *info;
12093
12094   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12095
12096   info = _clutter_actor_get_transform_info_or_defaults (self);
12097   clutter_anchor_coord_get_units (self, &info->anchor,
12098                                   anchor_x,
12099                                   anchor_y,
12100                                   NULL);
12101 }
12102
12103 /**
12104  * clutter_actor_set_anchor_point:
12105  * @self: a #ClutterActor
12106  * @anchor_x: X coordinate of the anchor point
12107  * @anchor_y: Y coordinate of the anchor point
12108  *
12109  * Sets an anchor point for @self. The anchor point is a point in the
12110  * coordinate space of an actor to which the actor position within its
12111  * parent is relative; the default is (0, 0), i.e. the top-left corner
12112  * of the actor.
12113  *
12114  * Since: 0.6
12115  */
12116 void
12117 clutter_actor_set_anchor_point (ClutterActor *self,
12118                                 gfloat        anchor_x,
12119                                 gfloat        anchor_y)
12120 {
12121   ClutterTransformInfo *info;
12122   ClutterActorPrivate *priv;
12123   gboolean changed = FALSE;
12124   gfloat old_anchor_x, old_anchor_y;
12125   GObject *obj;
12126
12127   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12128
12129   obj = G_OBJECT (self);
12130   priv = self->priv;
12131   info = _clutter_actor_get_transform_info (self);
12132
12133   g_object_freeze_notify (obj);
12134
12135   clutter_anchor_coord_get_units (self, &info->anchor,
12136                                   &old_anchor_x,
12137                                   &old_anchor_y,
12138                                   NULL);
12139
12140   if (info->anchor.is_fractional)
12141     g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12142
12143   if (old_anchor_x != anchor_x)
12144     {
12145       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12146       changed = TRUE;
12147     }
12148
12149   if (old_anchor_y != anchor_y)
12150     {
12151       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12152       changed = TRUE;
12153     }
12154
12155   clutter_anchor_coord_set_units (&info->anchor, anchor_x, anchor_y, 0);
12156
12157   if (changed)
12158     {
12159       priv->transform_valid = FALSE;
12160       clutter_actor_queue_redraw (self);
12161     }
12162
12163   g_object_thaw_notify (obj);
12164 }
12165
12166 /**
12167  * clutter_actor_get_anchor_point_gravity:
12168  * @self: a #ClutterActor
12169  *
12170  * Retrieves the anchor position expressed as a #ClutterGravity. If
12171  * the anchor point was specified using pixels or units this will
12172  * return %CLUTTER_GRAVITY_NONE.
12173  *
12174  * Return value: the #ClutterGravity used by the anchor point
12175  *
12176  * Since: 1.0
12177  */
12178 ClutterGravity
12179 clutter_actor_get_anchor_point_gravity (ClutterActor *self)
12180 {
12181   const ClutterTransformInfo *info;
12182
12183   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_GRAVITY_NONE);
12184
12185   info = _clutter_actor_get_transform_info_or_defaults (self);
12186
12187   return clutter_anchor_coord_get_gravity (&info->anchor);
12188 }
12189
12190 /**
12191  * clutter_actor_move_anchor_point:
12192  * @self: a #ClutterActor
12193  * @anchor_x: X coordinate of the anchor point
12194  * @anchor_y: Y coordinate of the anchor point
12195  *
12196  * Sets an anchor point for the actor, and adjusts the actor postion so that
12197  * the relative position of the actor toward its parent remains the same.
12198  *
12199  * Since: 0.6
12200  */
12201 void
12202 clutter_actor_move_anchor_point (ClutterActor *self,
12203                                  gfloat        anchor_x,
12204                                  gfloat        anchor_y)
12205 {
12206   gfloat old_anchor_x, old_anchor_y;
12207   const ClutterTransformInfo *info;
12208
12209   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12210
12211   info = _clutter_actor_get_transform_info (self);
12212   clutter_anchor_coord_get_units (self, &info->anchor,
12213                                   &old_anchor_x,
12214                                   &old_anchor_y,
12215                                   NULL);
12216
12217   g_object_freeze_notify (G_OBJECT (self));
12218
12219   clutter_actor_set_anchor_point (self, anchor_x, anchor_y);
12220
12221   if (self->priv->position_set)
12222     clutter_actor_move_by (self,
12223                            anchor_x - old_anchor_x,
12224                            anchor_y - old_anchor_y);
12225
12226   g_object_thaw_notify (G_OBJECT (self));
12227 }
12228
12229 /**
12230  * clutter_actor_move_anchor_point_from_gravity:
12231  * @self: a #ClutterActor
12232  * @gravity: #ClutterGravity.
12233  *
12234  * Sets an anchor point on the actor based on the given gravity, adjusting the
12235  * actor postion so that its relative position within its parent remains
12236  * unchanged.
12237  *
12238  * Since version 1.0 the anchor point will be stored as a gravity so
12239  * that if the actor changes size then the anchor point will move. For
12240  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12241  * and later double the size of the actor, the anchor point will move
12242  * to the bottom right.
12243  *
12244  * Since: 0.6
12245  */
12246 void
12247 clutter_actor_move_anchor_point_from_gravity (ClutterActor   *self,
12248                                               ClutterGravity  gravity)
12249 {
12250   gfloat old_anchor_x, old_anchor_y, new_anchor_x, new_anchor_y;
12251   const ClutterTransformInfo *info;
12252   ClutterActorPrivate *priv;
12253
12254   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12255
12256   priv = self->priv;
12257   info = _clutter_actor_get_transform_info (self);
12258
12259   g_object_freeze_notify (G_OBJECT (self));
12260
12261   clutter_anchor_coord_get_units (self, &info->anchor,
12262                                   &old_anchor_x,
12263                                   &old_anchor_y,
12264                                   NULL);
12265   clutter_actor_set_anchor_point_from_gravity (self, gravity);
12266   clutter_anchor_coord_get_units (self, &info->anchor,
12267                                   &new_anchor_x,
12268                                   &new_anchor_y,
12269                                   NULL);
12270
12271   if (priv->position_set)
12272     clutter_actor_move_by (self,
12273                            new_anchor_x - old_anchor_x,
12274                            new_anchor_y - old_anchor_y);
12275
12276   g_object_thaw_notify (G_OBJECT (self));
12277 }
12278
12279 /**
12280  * clutter_actor_set_anchor_point_from_gravity:
12281  * @self: a #ClutterActor
12282  * @gravity: #ClutterGravity.
12283  *
12284  * Sets an anchor point on the actor, based on the given gravity (this is a
12285  * convenience function wrapping clutter_actor_set_anchor_point()).
12286  *
12287  * Since version 1.0 the anchor point will be stored as a gravity so
12288  * that if the actor changes size then the anchor point will move. For
12289  * example, if you set the anchor point to %CLUTTER_GRAVITY_SOUTH_EAST
12290  * and later double the size of the actor, the anchor point will move
12291  * to the bottom right.
12292  *
12293  * Since: 0.6
12294  */
12295 void
12296 clutter_actor_set_anchor_point_from_gravity (ClutterActor   *self,
12297                                              ClutterGravity  gravity)
12298 {
12299   g_return_if_fail (CLUTTER_IS_ACTOR (self));
12300
12301   if (gravity == CLUTTER_GRAVITY_NONE)
12302     clutter_actor_set_anchor_point (self, 0, 0);
12303   else
12304     {
12305       GObject *obj = G_OBJECT (self);
12306       ClutterTransformInfo *info;
12307
12308       g_object_freeze_notify (obj);
12309
12310       info = _clutter_actor_get_transform_info (self);
12311       clutter_anchor_coord_set_gravity (&info->anchor, gravity);
12312
12313       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_GRAVITY]);
12314       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_X]);
12315       g_object_notify_by_pspec (obj, obj_props[PROP_ANCHOR_Y]);
12316
12317       self->priv->transform_valid = FALSE;
12318
12319       clutter_actor_queue_redraw (self);
12320
12321       g_object_thaw_notify (obj);
12322     }
12323 }
12324
12325 static void
12326 clutter_actor_store_content_box (ClutterActor *self,
12327                                  const ClutterActorBox *box)
12328 {
12329   if (box != NULL)
12330     {
12331       self->priv->content_box = *box;
12332       self->priv->content_box_valid = TRUE;
12333     }
12334   else
12335     self->priv->content_box_valid = FALSE;
12336
12337   clutter_actor_queue_redraw (self);
12338
12339   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
12340 }
12341
12342 static void
12343 clutter_container_iface_init (ClutterContainerIface *iface)
12344 {
12345   /* we don't override anything, as ClutterContainer already has a default
12346    * implementation that we can use, and which calls into our own API.
12347    */
12348 }
12349
12350 typedef enum
12351 {
12352   PARSE_X,
12353   PARSE_Y,
12354   PARSE_WIDTH,
12355   PARSE_HEIGHT,
12356   PARSE_ANCHOR_X,
12357   PARSE_ANCHOR_Y
12358 } ParseDimension;
12359
12360 static gfloat
12361 parse_units (ClutterActor   *self,
12362              ParseDimension  dimension,
12363              JsonNode       *node)
12364 {
12365   GValue value = G_VALUE_INIT;
12366   gfloat retval = 0;
12367
12368   if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
12369     return 0;
12370
12371   json_node_get_value (node, &value);
12372
12373   if (G_VALUE_HOLDS (&value, G_TYPE_INT64))
12374     {
12375       retval = (gfloat) g_value_get_int64 (&value);
12376     }
12377   else if (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE))
12378     {
12379       retval = g_value_get_double (&value);
12380     }
12381   else if (G_VALUE_HOLDS (&value, G_TYPE_STRING))
12382     {
12383       ClutterUnits units;
12384       gboolean res;
12385
12386       res = clutter_units_from_string (&units, g_value_get_string (&value));
12387       if (res)
12388         retval = clutter_units_to_pixels (&units);
12389       else
12390         {
12391           g_warning ("Invalid value '%s': integers, strings or floating point "
12392                      "values can be used for the x, y, width and height "
12393                      "properties. Valid modifiers for strings are 'px', 'mm', "
12394                      "'pt' and 'em'.",
12395                      g_value_get_string (&value));
12396           retval = 0;
12397         }
12398     }
12399   else
12400     {
12401       g_warning ("Invalid value of type '%s': integers, strings of floating "
12402                  "point values can be used for the x, y, width, height "
12403                  "anchor-x and anchor-y properties.",
12404                  g_type_name (G_VALUE_TYPE (&value)));
12405     }
12406
12407   g_value_unset (&value);
12408
12409   return retval;
12410 }
12411
12412 typedef struct {
12413   ClutterRotateAxis axis;
12414
12415   gdouble angle;
12416
12417   gfloat center_x;
12418   gfloat center_y;
12419   gfloat center_z;
12420 } RotationInfo;
12421
12422 static inline gboolean
12423 parse_rotation_array (ClutterActor *actor,
12424                       JsonArray    *array,
12425                       RotationInfo *info)
12426 {
12427   JsonNode *element;
12428
12429   if (json_array_get_length (array) != 2)
12430     return FALSE;
12431
12432   /* angle */
12433   element = json_array_get_element (array, 0);
12434   if (JSON_NODE_TYPE (element) == JSON_NODE_VALUE)
12435     info->angle = json_node_get_double (element);
12436   else
12437     return FALSE;
12438
12439   /* center */
12440   element = json_array_get_element (array, 1);
12441   if (JSON_NODE_TYPE (element) == JSON_NODE_ARRAY)
12442     {
12443       JsonArray *center = json_node_get_array (element);
12444
12445       if (json_array_get_length (center) != 2)
12446         return FALSE;
12447
12448       switch (info->axis)
12449         {
12450         case CLUTTER_X_AXIS:
12451           info->center_y = parse_units (actor, PARSE_Y,
12452                                         json_array_get_element (center, 0));
12453           info->center_z = parse_units (actor, PARSE_Y,
12454                                         json_array_get_element (center, 1));
12455           return TRUE;
12456
12457         case CLUTTER_Y_AXIS:
12458           info->center_x = parse_units (actor, PARSE_X,
12459                                         json_array_get_element (center, 0));
12460           info->center_z = parse_units (actor, PARSE_X,
12461                                         json_array_get_element (center, 1));
12462           return TRUE;
12463
12464         case CLUTTER_Z_AXIS:
12465           info->center_x = parse_units (actor, PARSE_X,
12466                                         json_array_get_element (center, 0));
12467           info->center_y = parse_units (actor, PARSE_Y,
12468                                         json_array_get_element (center, 1));
12469           return TRUE;
12470         }
12471     }
12472
12473   return FALSE;
12474 }
12475
12476 static gboolean
12477 parse_rotation (ClutterActor *actor,
12478                 JsonNode     *node,
12479                 RotationInfo *info)
12480 {
12481   JsonArray *array;
12482   guint len, i;
12483   gboolean retval = FALSE;
12484
12485   if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
12486     {
12487       g_warning ("Invalid node of type '%s' found, expecting an array",
12488                  json_node_type_name (node));
12489       return FALSE;
12490     }
12491
12492   array = json_node_get_array (node);
12493   len = json_array_get_length (array);
12494
12495   for (i = 0; i < len; i++)
12496     {
12497       JsonNode *element = json_array_get_element (array, i);
12498       JsonObject *object;
12499       JsonNode *member;
12500
12501       if (JSON_NODE_TYPE (element) != JSON_NODE_OBJECT)
12502         {
12503           g_warning ("Invalid node of type '%s' found, expecting an object",
12504                      json_node_type_name (element));
12505           return FALSE;
12506         }
12507
12508       object = json_node_get_object (element);
12509
12510       if (json_object_has_member (object, "x-axis"))
12511         {
12512           member = json_object_get_member (object, "x-axis");
12513
12514           info->axis = CLUTTER_X_AXIS;
12515
12516           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12517             {
12518               info->angle = json_node_get_double (member);
12519               retval = TRUE;
12520             }
12521           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12522             retval = parse_rotation_array (actor,
12523                                            json_node_get_array (member),
12524                                            info);
12525           else
12526             retval = FALSE;
12527         }
12528       else if (json_object_has_member (object, "y-axis"))
12529         {
12530           member = json_object_get_member (object, "y-axis");
12531
12532           info->axis = CLUTTER_Y_AXIS;
12533
12534           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12535             {
12536               info->angle = json_node_get_double (member);
12537               retval = TRUE;
12538             }
12539           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12540             retval = parse_rotation_array (actor,
12541                                            json_node_get_array (member),
12542                                            info);
12543           else
12544             retval = FALSE;
12545         }
12546       else if (json_object_has_member (object, "z-axis"))
12547         {
12548           member = json_object_get_member (object, "z-axis");
12549
12550           info->axis = CLUTTER_Z_AXIS;
12551
12552           if (JSON_NODE_TYPE (member) == JSON_NODE_VALUE)
12553             {
12554               info->angle = json_node_get_double (member);
12555               retval = TRUE;
12556             }
12557           else if (JSON_NODE_TYPE (member) == JSON_NODE_ARRAY)
12558             retval = parse_rotation_array (actor,
12559                                            json_node_get_array (member),
12560                                            info);
12561           else
12562             retval = FALSE;
12563         }
12564     }
12565
12566   return retval;
12567 }
12568
12569 static GSList *
12570 parse_actor_metas (ClutterScript *script,
12571                    ClutterActor  *actor,
12572                    JsonNode      *node)
12573 {
12574   GList *elements, *l;
12575   GSList *retval = NULL;
12576
12577   if (!JSON_NODE_HOLDS_ARRAY (node))
12578     return NULL;
12579
12580   elements = json_array_get_elements (json_node_get_array (node));
12581
12582   for (l = elements; l != NULL; l = l->next)
12583     {
12584       JsonNode *element = l->data;
12585       const gchar *id_ = _clutter_script_get_id_from_node (element);
12586       GObject *meta;
12587
12588       if (id_ == NULL || *id_ == '\0')
12589         continue;
12590
12591       meta = clutter_script_get_object (script, id_);
12592       if (meta == NULL)
12593         continue;
12594
12595       retval = g_slist_prepend (retval, meta);
12596     }
12597
12598   g_list_free (elements);
12599
12600   return g_slist_reverse (retval);
12601 }
12602
12603 static GSList *
12604 parse_behaviours (ClutterScript *script,
12605                   ClutterActor  *actor,
12606                   JsonNode      *node)
12607 {
12608   GList *elements, *l;
12609   GSList *retval = NULL;
12610
12611   if (!JSON_NODE_HOLDS_ARRAY (node))
12612     return NULL;
12613
12614   elements = json_array_get_elements (json_node_get_array (node));
12615
12616   for (l = elements; l != NULL; l = l->next)
12617     {
12618       JsonNode *element = l->data;
12619       const gchar *id_ = _clutter_script_get_id_from_node (element);
12620       GObject *behaviour;
12621
12622       if (id_ == NULL || *id_ == '\0')
12623         continue;
12624
12625       behaviour = clutter_script_get_object (script, id_);
12626       if (behaviour == NULL)
12627         continue;
12628
12629       retval = g_slist_prepend (retval, behaviour);
12630     }
12631
12632   g_list_free (elements);
12633
12634   return g_slist_reverse (retval);
12635 }
12636
12637 static gboolean
12638 clutter_actor_parse_custom_node (ClutterScriptable *scriptable,
12639                                  ClutterScript     *script,
12640                                  GValue            *value,
12641                                  const gchar       *name,
12642                                  JsonNode          *node)
12643 {
12644   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12645   gboolean retval = FALSE;
12646
12647   if ((name[0] == 'x' && name[1] == '\0') ||
12648       (name[0] == 'y' && name[1] == '\0') ||
12649       (strcmp (name, "width") == 0) ||
12650       (strcmp (name, "height") == 0) ||
12651       (strcmp (name, "anchor_x") == 0) ||
12652       (strcmp (name, "anchor_y") == 0))
12653     {
12654       ParseDimension dimension;
12655       gfloat units;
12656
12657       if (name[0] == 'x')
12658         dimension = PARSE_X;
12659       else if (name[0] == 'y')
12660         dimension = PARSE_Y;
12661       else if (name[0] == 'w')
12662         dimension = PARSE_WIDTH;
12663       else if (name[0] == 'h')
12664         dimension = PARSE_HEIGHT;
12665       else if (name[0] == 'a' && name[7] == 'x')
12666         dimension = PARSE_ANCHOR_X;
12667       else if (name[0] == 'a' && name[7] == 'y')
12668         dimension = PARSE_ANCHOR_Y;
12669       else
12670         return FALSE;
12671
12672       units = parse_units (actor, dimension, node);
12673
12674       /* convert back to pixels: all properties are pixel-based */
12675       g_value_init (value, G_TYPE_FLOAT);
12676       g_value_set_float (value, units);
12677
12678       retval = TRUE;
12679     }
12680   else if (strcmp (name, "rotation") == 0)
12681     {
12682       RotationInfo *info;
12683
12684       info = g_slice_new0 (RotationInfo);
12685       retval = parse_rotation (actor, node, info);
12686
12687       if (retval)
12688         {
12689           g_value_init (value, G_TYPE_POINTER);
12690           g_value_set_pointer (value, info);
12691         }
12692       else
12693         g_slice_free (RotationInfo, info);
12694     }
12695   else if (strcmp (name, "behaviours") == 0)
12696     {
12697       GSList *l;
12698
12699 #ifdef CLUTTER_ENABLE_DEBUG
12700       if (G_UNLIKELY (_clutter_diagnostic_enabled ()))
12701         _clutter_diagnostic_message ("The 'behaviours' key is deprecated "
12702                                      "and it should not be used in newly "
12703                                      "written ClutterScript definitions.");
12704 #endif
12705
12706       l = parse_behaviours (script, actor, node);
12707
12708       g_value_init (value, G_TYPE_POINTER);
12709       g_value_set_pointer (value, l);
12710
12711       retval = TRUE;
12712     }
12713   else if (strcmp (name, "actions") == 0 ||
12714            strcmp (name, "constraints") == 0 ||
12715            strcmp (name, "effects") == 0)
12716     {
12717       GSList *l;
12718
12719       l = parse_actor_metas (script, actor, node);
12720
12721       g_value_init (value, G_TYPE_POINTER);
12722       g_value_set_pointer (value, l);
12723
12724       retval = TRUE;
12725     }
12726
12727   return retval;
12728 }
12729
12730 static void
12731 clutter_actor_set_custom_property (ClutterScriptable *scriptable,
12732                                    ClutterScript     *script,
12733                                    const gchar       *name,
12734                                    const GValue      *value)
12735 {
12736   ClutterActor *actor = CLUTTER_ACTOR (scriptable);
12737
12738 #ifdef CLUTTER_ENABLE_DEBUG
12739   if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT)))
12740     {
12741       gchar *tmp = g_strdup_value_contents (value);
12742
12743       CLUTTER_NOTE (SCRIPT,
12744                     "in ClutterActor::set_custom_property('%s') = %s",
12745                     name,
12746                     tmp);
12747
12748       g_free (tmp);
12749     }
12750 #endif /* CLUTTER_ENABLE_DEBUG */
12751
12752   if (strcmp (name, "rotation") == 0)
12753     {
12754       RotationInfo *info;
12755
12756       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12757         return;
12758
12759       info = g_value_get_pointer (value);
12760
12761       clutter_actor_set_rotation (actor,
12762                                   info->axis, info->angle,
12763                                   info->center_x,
12764                                   info->center_y,
12765                                   info->center_z);
12766
12767       g_slice_free (RotationInfo, info);
12768
12769       return;
12770     }
12771
12772   if (strcmp (name, "behaviours") == 0)
12773     {
12774       GSList *behaviours, *l;
12775
12776       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12777         return;
12778
12779       behaviours = g_value_get_pointer (value);
12780       for (l = behaviours; l != NULL; l = l->next)
12781         {
12782           ClutterBehaviour *behaviour = l->data;
12783
12784           clutter_behaviour_apply (behaviour, actor);
12785         }
12786
12787       g_slist_free (behaviours);
12788
12789       return;
12790     }
12791
12792   if (strcmp (name, "actions") == 0 ||
12793       strcmp (name, "constraints") == 0 ||
12794       strcmp (name, "effects") == 0)
12795     {
12796       GSList *metas, *l;
12797
12798       if (!G_VALUE_HOLDS (value, G_TYPE_POINTER))
12799         return;
12800
12801       metas = g_value_get_pointer (value);
12802       for (l = metas; l != NULL; l = l->next)
12803         {
12804           if (name[0] == 'a')
12805             clutter_actor_add_action (actor, l->data);
12806
12807           if (name[0] == 'c')
12808             clutter_actor_add_constraint (actor, l->data);
12809
12810           if (name[0] == 'e')
12811             clutter_actor_add_effect (actor, l->data);
12812         }
12813
12814       g_slist_free (metas);
12815
12816       return;
12817     }
12818
12819   g_object_set_property (G_OBJECT (scriptable), name, value);
12820 }
12821
12822 static void
12823 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
12824 {
12825   iface->parse_custom_node = clutter_actor_parse_custom_node;
12826   iface->set_custom_property = clutter_actor_set_custom_property;
12827 }
12828
12829 static ClutterActorMeta *
12830 get_meta_from_animation_property (ClutterActor  *actor,
12831                                   const gchar   *name,
12832                                   gchar        **name_p)
12833 {
12834   ClutterActorPrivate *priv = actor->priv;
12835   ClutterActorMeta *meta = NULL;
12836   gchar **tokens;
12837
12838   /* if this is not a special property, fall through */
12839   if (name[0] != '@')
12840     return NULL;
12841
12842   /* detect the properties named using the following spec:
12843    *
12844    *   @<section>.<meta-name>.<property-name>
12845    *
12846    * where <section> can be one of the following:
12847    *
12848    *   - actions
12849    *   - constraints
12850    *   - effects
12851    *
12852    * and <meta-name> is the name set on a specific ActorMeta
12853    */
12854
12855   tokens = g_strsplit (name + 1, ".", -1);
12856   if (tokens == NULL || g_strv_length (tokens) != 3)
12857     {
12858       CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
12859                     name + 1);
12860       g_strfreev (tokens);
12861       return NULL;
12862     }
12863
12864   if (strcmp (tokens[0], "actions") == 0)
12865     meta = _clutter_meta_group_get_meta (priv->actions, tokens[1]);
12866
12867   if (strcmp (tokens[0], "constraints") == 0)
12868     meta = _clutter_meta_group_get_meta (priv->constraints, tokens[1]);
12869
12870   if (strcmp (tokens[0], "effects") == 0)
12871     meta = _clutter_meta_group_get_meta (priv->effects, tokens[1]);
12872
12873   if (name_p != NULL)
12874     *name_p = g_strdup (tokens[2]);
12875
12876   CLUTTER_NOTE (ANIMATION,
12877                 "Looking for property '%s' of object '%s' in section '%s'",
12878                 tokens[2],
12879                 tokens[1],
12880                 tokens[0]);
12881
12882   g_strfreev (tokens);
12883
12884   return meta;
12885 }
12886
12887 static GParamSpec *
12888 clutter_actor_find_property (ClutterAnimatable *animatable,
12889                              const gchar       *property_name)
12890 {
12891   ClutterActorMeta *meta = NULL;
12892   GObjectClass *klass = NULL;
12893   GParamSpec *pspec = NULL;
12894   gchar *p_name = NULL;
12895
12896   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12897                                            property_name,
12898                                            &p_name);
12899
12900   if (meta != NULL)
12901     {
12902       klass = G_OBJECT_GET_CLASS (meta);
12903
12904       pspec = g_object_class_find_property (klass, p_name);
12905     }
12906   else
12907     {
12908       klass = G_OBJECT_GET_CLASS (animatable);
12909
12910       pspec = g_object_class_find_property (klass, property_name);
12911     }
12912
12913   g_free (p_name);
12914
12915   return pspec;
12916 }
12917
12918 static void
12919 clutter_actor_get_initial_state (ClutterAnimatable *animatable,
12920                                  const gchar       *property_name,
12921                                  GValue            *initial)
12922 {
12923   ClutterActorMeta *meta = NULL;
12924   gchar *p_name = NULL;
12925
12926   meta = get_meta_from_animation_property (CLUTTER_ACTOR (animatable),
12927                                            property_name,
12928                                            &p_name);
12929
12930   if (meta != NULL)
12931     g_object_get_property (G_OBJECT (meta), p_name, initial);
12932   else
12933     g_object_get_property (G_OBJECT (animatable), property_name, initial);
12934
12935   g_free (p_name);
12936 }
12937
12938 /*
12939  * clutter_actor_set_animatable_property:
12940  * @actor: a #ClutterActor
12941  * @prop_id: the paramspec id
12942  * @value: the value to set
12943  * @pspec: the paramspec
12944  *
12945  * Sets values of animatable properties.
12946  *
12947  * This is a variant of clutter_actor_set_property() that gets called
12948  * by the #ClutterAnimatable implementation of #ClutterActor for the
12949  * properties with the %CLUTTER_PARAM_ANIMATABLE flag set on their
12950  * #GParamSpec.
12951  *
12952  * Unlike the implementation of #GObjectClass.set_property(), this
12953  * function will not update the interval if a transition involving an
12954  * animatable property is in progress - this avoids cycles with the
12955  * transition API calling the public API.
12956  */
12957 static void
12958 clutter_actor_set_animatable_property (ClutterActor *actor,
12959                                        guint         prop_id,
12960                                        const GValue *value,
12961                                        GParamSpec   *pspec)
12962 {
12963   GObject *obj = G_OBJECT (actor);
12964
12965   g_object_freeze_notify (obj);
12966
12967   switch (prop_id)
12968     {
12969     case PROP_X:
12970       clutter_actor_set_x_internal (actor, g_value_get_float (value));
12971       break;
12972
12973     case PROP_Y:
12974       clutter_actor_set_y_internal (actor, g_value_get_float (value));
12975       break;
12976
12977     case PROP_WIDTH:
12978       clutter_actor_set_width_internal (actor, g_value_get_float (value));
12979       break;
12980
12981     case PROP_HEIGHT:
12982       clutter_actor_set_height_internal (actor, g_value_get_float (value));
12983       break;
12984
12985     case PROP_DEPTH:
12986       clutter_actor_set_depth_internal (actor, g_value_get_float (value));
12987       break;
12988
12989     case PROP_OPACITY:
12990       clutter_actor_set_opacity_internal (actor, g_value_get_uint (value));
12991       break;
12992
12993     case PROP_BACKGROUND_COLOR:
12994       clutter_actor_set_background_color_internal (actor, clutter_value_get_color (value));
12995       break;
12996
12997     case PROP_SCALE_X:
12998       clutter_actor_set_scale_factor_internal (actor,
12999                                                g_value_get_double (value),
13000                                                pspec);
13001       break;
13002
13003     case PROP_SCALE_Y:
13004       clutter_actor_set_scale_factor_internal (actor,
13005                                                g_value_get_double (value),
13006                                                pspec);
13007       break;
13008
13009     case PROP_ROTATION_ANGLE_X:
13010       clutter_actor_set_rotation_angle_internal (actor,
13011                                                  CLUTTER_X_AXIS,
13012                                                  g_value_get_double (value));
13013       break;
13014
13015     case PROP_ROTATION_ANGLE_Y:
13016       clutter_actor_set_rotation_angle_internal (actor,
13017                                                  CLUTTER_Y_AXIS,
13018                                                  g_value_get_double (value));
13019       break;
13020
13021     case PROP_ROTATION_ANGLE_Z:
13022       clutter_actor_set_rotation_angle_internal (actor,
13023                                                  CLUTTER_Z_AXIS,
13024                                                  g_value_get_double (value));
13025       break;
13026
13027     case PROP_CONTENT_BOX:
13028       clutter_actor_store_content_box (actor, g_value_get_boxed (value));
13029       break;
13030
13031     default:
13032       g_object_set_property (obj, pspec->name, value);
13033       break;
13034     }
13035
13036   g_object_thaw_notify (obj);
13037 }
13038
13039 static void
13040 clutter_actor_set_final_state (ClutterAnimatable *animatable,
13041                                const gchar       *property_name,
13042                                const GValue      *final)
13043 {
13044   ClutterActor *actor = CLUTTER_ACTOR (animatable);
13045   ClutterActorMeta *meta = NULL;
13046   gchar *p_name = NULL;
13047
13048   meta = get_meta_from_animation_property (actor,
13049                                            property_name,
13050                                            &p_name);
13051   if (meta != NULL)
13052     g_object_set_property (G_OBJECT (meta), p_name, final);
13053   else
13054     {
13055       GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
13056       GParamSpec *pspec;
13057
13058       pspec = g_object_class_find_property (obj_class, property_name);
13059
13060       if ((pspec->flags & CLUTTER_PARAM_ANIMATABLE) != 0)
13061         {
13062           /* XXX - I'm going to the special hell for this */
13063           clutter_actor_set_animatable_property (actor, pspec->param_id, final, pspec);
13064         }
13065       else
13066         g_object_set_property (G_OBJECT (animatable), pspec->name, final);
13067     }
13068
13069   g_free (p_name);
13070 }
13071
13072 static void
13073 clutter_animatable_iface_init (ClutterAnimatableIface *iface)
13074 {
13075   iface->find_property = clutter_actor_find_property;
13076   iface->get_initial_state = clutter_actor_get_initial_state;
13077   iface->set_final_state = clutter_actor_set_final_state;
13078 }
13079
13080 /**
13081  * clutter_actor_transform_stage_point:
13082  * @self: A #ClutterActor
13083  * @x: (in): x screen coordinate of the point to unproject
13084  * @y: (in): y screen coordinate of the point to unproject
13085  * @x_out: (out): return location for the unprojected x coordinance
13086  * @y_out: (out): return location for the unprojected y coordinance
13087  *
13088  * This function translates screen coordinates (@x, @y) to
13089  * coordinates relative to the actor. For example, it can be used to translate
13090  * screen events from global screen coordinates into actor-local coordinates.
13091  *
13092  * The conversion can fail, notably if the transform stack results in the
13093  * actor being projected on the screen as a mere line.
13094  *
13095  * The conversion should not be expected to be pixel-perfect due to the
13096  * nature of the operation. In general the error grows when the skewing
13097  * of the actor rectangle on screen increases.
13098  *
13099  * <note><para>This function can be computationally intensive.</para></note>
13100  *
13101  * <note><para>This function only works when the allocation is up-to-date,
13102  * i.e. inside of paint().</para></note>
13103  *
13104  * Return value: %TRUE if conversion was successful.
13105  *
13106  * Since: 0.6
13107  */
13108 gboolean
13109 clutter_actor_transform_stage_point (ClutterActor *self,
13110                                      gfloat        x,
13111                                      gfloat        y,
13112                                      gfloat       *x_out,
13113                                      gfloat       *y_out)
13114 {
13115   ClutterVertex v[4];
13116   float ST[3][3];
13117   float RQ[3][3];
13118   int du, dv, xi, yi;
13119   float px, py;
13120   float xf, yf, wf, det;
13121   ClutterActorPrivate *priv;
13122
13123   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13124
13125   priv = self->priv;
13126
13127   /* This implementation is based on the quad -> quad projection algorithm
13128    * described by Paul Heckbert in:
13129    *
13130    *   http://www.cs.cmu.edu/~ph/texfund/texfund.pdf
13131    *
13132    * and the sample implementation at:
13133    *
13134    *   http://www.cs.cmu.edu/~ph/src/texfund/
13135    *
13136    * Our texture is a rectangle with origin [0, 0], so we are mapping from
13137    * quad to rectangle only, which significantly simplifies things; the
13138    * function calls have been unrolled, and most of the math is done in fixed
13139    * point.
13140    */
13141
13142   clutter_actor_get_abs_allocation_vertices (self, v);
13143
13144   /* Keeping these as ints simplifies the multiplication (no significant
13145    * loss of precision here).
13146    */
13147   du = (int) (priv->allocation.x2 - priv->allocation.x1);
13148   dv = (int) (priv->allocation.y2 - priv->allocation.y1);
13149
13150   if (!du || !dv)
13151     return FALSE;
13152
13153 #define UX2FP(x)        (x)
13154 #define DET2FP(a,b,c,d) (((a) * (d)) - ((b) * (c)))
13155
13156   /* First, find mapping from unit uv square to xy quadrilateral; this
13157    * equivalent to the pmap_square_quad() functions in the sample
13158    * implementation, which we can simplify, since our target is always
13159    * a rectangle.
13160    */
13161   px = v[0].x - v[1].x + v[3].x - v[2].x;
13162   py = v[0].y - v[1].y + v[3].y - v[2].y;
13163
13164   if (!px && !py)
13165     {
13166       /* affine transform */
13167       RQ[0][0] = UX2FP (v[1].x - v[0].x);
13168       RQ[1][0] = UX2FP (v[3].x - v[1].x);
13169       RQ[2][0] = UX2FP (v[0].x);
13170       RQ[0][1] = UX2FP (v[1].y - v[0].y);
13171       RQ[1][1] = UX2FP (v[3].y - v[1].y);
13172       RQ[2][1] = UX2FP (v[0].y);
13173       RQ[0][2] = 0;
13174       RQ[1][2] = 0;
13175       RQ[2][2] = 1.0;
13176     }
13177   else
13178     {
13179       /* projective transform */
13180       double dx1, dx2, dy1, dy2, del;
13181
13182       dx1 = UX2FP (v[1].x - v[3].x);
13183       dx2 = UX2FP (v[2].x - v[3].x);
13184       dy1 = UX2FP (v[1].y - v[3].y);
13185       dy2 = UX2FP (v[2].y - v[3].y);
13186
13187       del = DET2FP (dx1, dx2, dy1, dy2);
13188       if (!del)
13189         return FALSE;
13190
13191       /*
13192        * The division here needs to be done in floating point for
13193        * precisions reasons.
13194        */
13195       RQ[0][2] = (DET2FP (UX2FP (px), dx2, UX2FP (py), dy2) / del);
13196       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13197       RQ[1][2] = (DET2FP (dx1, UX2FP (px), dy1, UX2FP (py)) / del);
13198       RQ[2][2] = 1.0;
13199       RQ[0][0] = UX2FP (v[1].x - v[0].x) + (RQ[0][2] * UX2FP (v[1].x));
13200       RQ[1][0] = UX2FP (v[2].x - v[0].x) + (RQ[1][2] * UX2FP (v[2].x));
13201       RQ[2][0] = UX2FP (v[0].x);
13202       RQ[0][1] = UX2FP (v[1].y - v[0].y) + (RQ[0][2] * UX2FP (v[1].y));
13203       RQ[1][1] = UX2FP (v[2].y - v[0].y) + (RQ[1][2] * UX2FP (v[2].y));
13204       RQ[2][1] = UX2FP (v[0].y);
13205     }
13206
13207   /*
13208    * Now combine with transform from our rectangle (u0,v0,u1,v1) to unit
13209    * square. Since our rectangle is based at 0,0 we only need to scale.
13210    */
13211   RQ[0][0] /= du;
13212   RQ[1][0] /= dv;
13213   RQ[0][1] /= du;
13214   RQ[1][1] /= dv;
13215   RQ[0][2] /= du;
13216   RQ[1][2] /= dv;
13217
13218   /*
13219    * Now RQ is transform from uv rectangle to xy quadrilateral; we need an
13220    * inverse of that.
13221    */
13222   ST[0][0] = DET2FP (RQ[1][1], RQ[1][2], RQ[2][1], RQ[2][2]);
13223   ST[1][0] = DET2FP (RQ[1][2], RQ[1][0], RQ[2][2], RQ[2][0]);
13224   ST[2][0] = DET2FP (RQ[1][0], RQ[1][1], RQ[2][0], RQ[2][1]);
13225   ST[0][1] = DET2FP (RQ[2][1], RQ[2][2], RQ[0][1], RQ[0][2]);
13226   ST[1][1] = DET2FP (RQ[2][2], RQ[2][0], RQ[0][2], RQ[0][0]);
13227   ST[2][1] = DET2FP (RQ[2][0], RQ[2][1], RQ[0][0], RQ[0][1]);
13228   ST[0][2] = DET2FP (RQ[0][1], RQ[0][2], RQ[1][1], RQ[1][2]);
13229   ST[1][2] = DET2FP (RQ[0][2], RQ[0][0], RQ[1][2], RQ[1][0]);
13230   ST[2][2] = DET2FP (RQ[0][0], RQ[0][1], RQ[1][0], RQ[1][1]);
13231
13232   /*
13233    * Check the resulting matrix is OK.
13234    */
13235   det = (RQ[0][0] * ST[0][0])
13236       + (RQ[0][1] * ST[0][1])
13237       + (RQ[0][2] * ST[0][2]);
13238   if (!det)
13239     return FALSE;
13240
13241   /*
13242    * Now transform our point with the ST matrix; the notional w
13243    * coordinate is 1, hence the last part is simply added.
13244    */
13245   xi = (int) x;
13246   yi = (int) y;
13247
13248   xf = xi * ST[0][0] + yi * ST[1][0] + ST[2][0];
13249   yf = xi * ST[0][1] + yi * ST[1][1] + ST[2][1];
13250   wf = xi * ST[0][2] + yi * ST[1][2] + ST[2][2];
13251
13252   if (x_out)
13253     *x_out = xf / wf;
13254
13255   if (y_out)
13256     *y_out = yf / wf;
13257
13258 #undef UX2FP
13259 #undef DET2FP
13260
13261   return TRUE;
13262 }
13263
13264 /*
13265  * ClutterGeometry
13266  */
13267
13268 static ClutterGeometry*
13269 clutter_geometry_copy (const ClutterGeometry *geometry)
13270 {
13271   return g_slice_dup (ClutterGeometry, geometry);
13272 }
13273
13274 static void
13275 clutter_geometry_free (ClutterGeometry *geometry)
13276 {
13277   if (G_LIKELY (geometry != NULL))
13278     g_slice_free (ClutterGeometry, geometry);
13279 }
13280
13281 /**
13282  * clutter_geometry_union:
13283  * @geometry_a: a #ClutterGeometry
13284  * @geometry_b: another #ClutterGeometry
13285  * @result: (out): location to store the result
13286  *
13287  * Find the union of two rectangles represented as #ClutterGeometry.
13288  *
13289  * Since: 1.4
13290  */
13291 void
13292 clutter_geometry_union (const ClutterGeometry *geometry_a,
13293                         const ClutterGeometry *geometry_b,
13294                         ClutterGeometry       *result)
13295 {
13296   /* We don't try to handle rectangles that can't be represented
13297    * as a signed integer box */
13298   gint x_1 = MIN (geometry_a->x, geometry_b->x);
13299   gint y_1 = MIN (geometry_a->y, geometry_b->y);
13300   gint x_2 = MAX (geometry_a->x + (gint)geometry_a->width,
13301                   geometry_b->x + (gint)geometry_b->width);
13302   gint y_2 = MAX (geometry_a->y + (gint)geometry_a->height,
13303                   geometry_b->y + (gint)geometry_b->height);
13304   result->x = x_1;
13305   result->y = y_1;
13306   result->width = x_2 - x_1;
13307   result->height = y_2 - y_1;
13308 }
13309
13310 /**
13311  * clutter_geometry_intersects:
13312  * @geometry0: The first geometry to test
13313  * @geometry1: The second geometry to test
13314  *
13315  * Determines if @geometry0 and geometry1 intersect returning %TRUE if
13316  * they do else %FALSE.
13317  *
13318  * Return value: %TRUE of @geometry0 and geometry1 intersect else
13319  * %FALSE.
13320  *
13321  * Since: 1.4
13322  */
13323 gboolean
13324 clutter_geometry_intersects (const ClutterGeometry *geometry0,
13325                              const ClutterGeometry *geometry1)
13326 {
13327   if (geometry1->x >= (geometry0->x + (gint)geometry0->width) ||
13328       geometry1->y >= (geometry0->y + (gint)geometry0->height) ||
13329       (geometry1->x + (gint)geometry1->width) <= geometry0->x ||
13330       (geometry1->y + (gint)geometry1->height) <= geometry0->y)
13331     return FALSE;
13332   else
13333     return TRUE;
13334 }
13335
13336 static gboolean
13337 clutter_geometry_progress (const GValue *a,
13338                            const GValue *b,
13339                            gdouble       progress,
13340                            GValue       *retval)
13341 {
13342   const ClutterGeometry *a_geom = g_value_get_boxed (a);
13343   const ClutterGeometry *b_geom = g_value_get_boxed (b);
13344   ClutterGeometry res = { 0, };
13345   gint a_width = a_geom->width;
13346   gint b_width = b_geom->width;
13347   gint a_height = a_geom->height;
13348   gint b_height = b_geom->height;
13349
13350   res.x = a_geom->x + (b_geom->x - a_geom->x) * progress;
13351   res.y = a_geom->y + (b_geom->y - a_geom->y) * progress;
13352
13353   res.width = a_width + (b_width - a_width) * progress;
13354   res.height = a_height + (b_height - a_height) * progress;
13355
13356   g_value_set_boxed (retval, &res);
13357
13358   return TRUE;
13359 }
13360
13361 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterGeometry, clutter_geometry,
13362                                clutter_geometry_copy,
13363                                clutter_geometry_free,
13364                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_geometry_progress));
13365
13366 /*
13367  * ClutterVertices
13368  */
13369
13370 /**
13371  * clutter_vertex_new:
13372  * @x: X coordinate
13373  * @y: Y coordinate
13374  * @z: Z coordinate
13375  *
13376  * Creates a new #ClutterVertex for the point in 3D space
13377  * identified by the 3 coordinates @x, @y, @z
13378  *
13379  * Return value: the newly allocate #ClutterVertex. Use
13380  *   clutter_vertex_free() to free the resources
13381  *
13382  * Since: 1.0
13383  */
13384 ClutterVertex *
13385 clutter_vertex_new (gfloat x,
13386                     gfloat y,
13387                     gfloat z)
13388 {
13389   ClutterVertex *vertex;
13390
13391   vertex = g_slice_new (ClutterVertex);
13392   clutter_vertex_init (vertex, x, y, z);
13393
13394   return vertex;
13395 }
13396
13397 /**
13398  * clutter_vertex_init:
13399  * @vertex: a #ClutterVertex
13400  * @x: X coordinate
13401  * @y: Y coordinate
13402  * @z: Z coordinate
13403  *
13404  * Initializes @vertex with the given coordinates.
13405  *
13406  * Since: 1.10
13407  */
13408 void
13409 clutter_vertex_init (ClutterVertex *vertex,
13410                      gfloat         x,
13411                      gfloat         y,
13412                      gfloat         z)
13413 {
13414   g_return_if_fail (vertex != NULL);
13415
13416   vertex->x = x;
13417   vertex->y = y;
13418   vertex->z = z;
13419 }
13420
13421 /**
13422  * clutter_vertex_copy:
13423  * @vertex: a #ClutterVertex
13424  *
13425  * Copies @vertex
13426  *
13427  * Return value: a newly allocated copy of #ClutterVertex. Use
13428  *   clutter_vertex_free() to free the allocated resources
13429  *
13430  * Since: 1.0
13431  */
13432 ClutterVertex *
13433 clutter_vertex_copy (const ClutterVertex *vertex)
13434 {
13435   if (G_LIKELY (vertex != NULL))
13436     return g_slice_dup (ClutterVertex, vertex);
13437
13438   return NULL;
13439 }
13440
13441 /**
13442  * clutter_vertex_free:
13443  * @vertex: a #ClutterVertex
13444  *
13445  * Frees a #ClutterVertex allocated using clutter_vertex_copy()
13446  *
13447  * Since: 1.0
13448  */
13449 void
13450 clutter_vertex_free (ClutterVertex *vertex)
13451 {
13452   if (G_UNLIKELY (vertex != NULL))
13453     g_slice_free (ClutterVertex, vertex);
13454 }
13455
13456 /**
13457  * clutter_vertex_equal:
13458  * @vertex_a: a #ClutterVertex
13459  * @vertex_b: a #ClutterVertex
13460  *
13461  * Compares @vertex_a and @vertex_b for equality
13462  *
13463  * Return value: %TRUE if the passed #ClutterVertex are equal
13464  *
13465  * Since: 1.0
13466  */
13467 gboolean
13468 clutter_vertex_equal (const ClutterVertex *vertex_a,
13469                       const ClutterVertex *vertex_b)
13470 {
13471   g_return_val_if_fail (vertex_a != NULL && vertex_b != NULL, FALSE);
13472
13473   if (vertex_a == vertex_b)
13474     return TRUE;
13475
13476   return vertex_a->x == vertex_b->x &&
13477          vertex_a->y == vertex_b->y &&
13478          vertex_a->z == vertex_b->z;
13479 }
13480
13481 static gboolean
13482 clutter_vertex_progress (const GValue *a,
13483                          const GValue *b,
13484                          gdouble       progress,
13485                          GValue       *retval)
13486 {
13487   const ClutterVertex *av = g_value_get_boxed (a);
13488   const ClutterVertex *bv = g_value_get_boxed (b);
13489   ClutterVertex res = { 0, };
13490
13491   res.x = av->x + (bv->x - av->x) * progress;
13492   res.y = av->y + (bv->y - av->y) * progress;
13493   res.z = av->z + (bv->z - av->z) * progress;
13494
13495   g_value_set_boxed (retval, &res);
13496
13497   return TRUE;
13498 }
13499
13500 G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterVertex, clutter_vertex,
13501                                clutter_vertex_copy,
13502                                clutter_vertex_free,
13503                                CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_vertex_progress));
13504
13505 /**
13506  * clutter_actor_is_rotated:
13507  * @self: a #ClutterActor
13508  *
13509  * Checks whether any rotation is applied to the actor.
13510  *
13511  * Return value: %TRUE if the actor is rotated.
13512  *
13513  * Since: 0.6
13514  */
13515 gboolean
13516 clutter_actor_is_rotated (ClutterActor *self)
13517 {
13518   const ClutterTransformInfo *info;
13519
13520   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13521
13522   info = _clutter_actor_get_transform_info_or_defaults (self);
13523
13524   if (info->rx_angle || info->ry_angle || info->rz_angle)
13525     return TRUE;
13526
13527   return FALSE;
13528 }
13529
13530 /**
13531  * clutter_actor_is_scaled:
13532  * @self: a #ClutterActor
13533  *
13534  * Checks whether the actor is scaled in either dimension.
13535  *
13536  * Return value: %TRUE if the actor is scaled.
13537  *
13538  * Since: 0.6
13539  */
13540 gboolean
13541 clutter_actor_is_scaled (ClutterActor *self)
13542 {
13543   const ClutterTransformInfo *info;
13544
13545   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
13546
13547   info = _clutter_actor_get_transform_info_or_defaults (self);
13548
13549   if (info->scale_x != 1.0 || info->scale_y != 1.0)
13550     return TRUE;
13551
13552   return FALSE;
13553 }
13554
13555 ClutterActor *
13556 _clutter_actor_get_stage_internal (ClutterActor *actor)
13557 {
13558   while (actor && !CLUTTER_ACTOR_IS_TOPLEVEL (actor))
13559     actor = actor->priv->parent;
13560
13561   return actor;
13562 }
13563
13564 /**
13565  * clutter_actor_get_stage:
13566  * @actor: a #ClutterActor
13567  *
13568  * Retrieves the #ClutterStage where @actor is contained.
13569  *
13570  * Return value: (transfer none) (type Clutter.Stage): the stage
13571  *   containing the actor, or %NULL
13572  *
13573  * Since: 0.8
13574  */
13575 ClutterActor *
13576 clutter_actor_get_stage (ClutterActor *actor)
13577 {
13578   g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
13579
13580   return _clutter_actor_get_stage_internal (actor);
13581 }
13582
13583 /**
13584  * clutter_actor_allocate_available_size:
13585  * @self: a #ClutterActor
13586  * @x: the actor's X coordinate
13587  * @y: the actor's Y coordinate
13588  * @available_width: the maximum available width, or -1 to use the
13589  *   actor's natural width
13590  * @available_height: the maximum available height, or -1 to use the
13591  *   actor's natural height
13592  * @flags: flags controlling the allocation
13593  *
13594  * Allocates @self taking into account the #ClutterActor<!-- -->'s
13595  * preferred size, but limiting it to the maximum available width
13596  * and height provided.
13597  *
13598  * This function will do the right thing when dealing with the
13599  * actor's request mode.
13600  *
13601  * The implementation of this function is equivalent to:
13602  *
13603  * |[
13604  *   if (request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13605  *     {
13606  *       clutter_actor_get_preferred_width (self, available_height,
13607  *                                          &amp;min_width,
13608  *                                          &amp;natural_width);
13609  *       width = CLAMP (natural_width, min_width, available_width);
13610  *
13611  *       clutter_actor_get_preferred_height (self, width,
13612  *                                           &amp;min_height,
13613  *                                           &amp;natural_height);
13614  *       height = CLAMP (natural_height, min_height, available_height);
13615  *     }
13616  *   else
13617  *     {
13618  *       clutter_actor_get_preferred_height (self, available_width,
13619  *                                           &amp;min_height,
13620  *                                           &amp;natural_height);
13621  *       height = CLAMP (natural_height, min_height, available_height);
13622  *
13623  *       clutter_actor_get_preferred_width (self, height,
13624  *                                          &amp;min_width,
13625  *                                          &amp;natural_width);
13626  *       width = CLAMP (natural_width, min_width, available_width);
13627  *     }
13628  *
13629  *   box.x1 = x; box.y1 = y;
13630  *   box.x2 = box.x1 + available_width;
13631  *   box.y2 = box.y1 + available_height;
13632  *   clutter_actor_allocate (self, &amp;box, flags);
13633  * ]|
13634  *
13635  * This function can be used by fluid layout managers to allocate
13636  * an actor's preferred size without making it bigger than the area
13637  * available for the container.
13638  *
13639  * Since: 1.0
13640  */
13641 void
13642 clutter_actor_allocate_available_size (ClutterActor           *self,
13643                                        gfloat                  x,
13644                                        gfloat                  y,
13645                                        gfloat                  available_width,
13646                                        gfloat                  available_height,
13647                                        ClutterAllocationFlags  flags)
13648 {
13649   ClutterActorPrivate *priv;
13650   gfloat width, height;
13651   gfloat min_width, min_height;
13652   gfloat natural_width, natural_height;
13653   ClutterActorBox box;
13654
13655   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13656
13657   priv = self->priv;
13658
13659   width = height = 0.0;
13660
13661   switch (priv->request_mode)
13662     {
13663     case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
13664       clutter_actor_get_preferred_width (self, available_height,
13665                                          &min_width,
13666                                          &natural_width);
13667       width  = CLAMP (natural_width, min_width, available_width);
13668
13669       clutter_actor_get_preferred_height (self, width,
13670                                           &min_height,
13671                                           &natural_height);
13672       height = CLAMP (natural_height, min_height, available_height);
13673       break;
13674
13675     case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
13676       clutter_actor_get_preferred_height (self, available_width,
13677                                           &min_height,
13678                                           &natural_height);
13679       height = CLAMP (natural_height, min_height, available_height);
13680
13681       clutter_actor_get_preferred_width (self, height,
13682                                          &min_width,
13683                                          &natural_width);
13684       width  = CLAMP (natural_width, min_width, available_width);
13685       break;
13686     }
13687
13688
13689   box.x1 = x;
13690   box.y1 = y;
13691   box.x2 = box.x1 + width;
13692   box.y2 = box.y1 + height;
13693   clutter_actor_allocate (self, &box, flags);
13694 }
13695
13696 /**
13697  * clutter_actor_allocate_preferred_size:
13698  * @self: a #ClutterActor
13699  * @flags: flags controlling the allocation
13700  *
13701  * Allocates the natural size of @self.
13702  *
13703  * This function is a utility call for #ClutterActor implementations
13704  * that allocates the actor's preferred natural size. It can be used
13705  * by fixed layout managers (like #ClutterGroup or so called
13706  * 'composite actors') inside the ClutterActor::allocate
13707  * implementation to give each child exactly how much space it
13708  * requires.
13709  *
13710  * This function is not meant to be used by applications. It is also
13711  * not meant to be used outside the implementation of the
13712  * ClutterActor::allocate virtual function.
13713  *
13714  * Since: 0.8
13715  */
13716 void
13717 clutter_actor_allocate_preferred_size (ClutterActor           *self,
13718                                        ClutterAllocationFlags  flags)
13719 {
13720   gfloat actor_x, actor_y;
13721   gfloat natural_width, natural_height;
13722   ClutterActorBox actor_box;
13723
13724   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13725
13726   actor_x = clutter_actor_get_x (self);
13727   actor_y = clutter_actor_get_y (self);
13728
13729   clutter_actor_get_preferred_size (self,
13730                                     NULL, NULL,
13731                                     &natural_width,
13732                                     &natural_height);
13733
13734   actor_box.x1 = actor_x;
13735   actor_box.y1 = actor_y;
13736   actor_box.x2 = actor_box.x1 + natural_width;
13737   actor_box.y2 = actor_box.y1 + natural_height;
13738
13739   clutter_actor_allocate (self, &actor_box, flags);
13740 }
13741
13742 /**
13743  * clutter_actor_allocate_align_fill:
13744  * @self: a #ClutterActor
13745  * @box: a #ClutterActorBox, containing the available width and height
13746  * @x_align: the horizontal alignment, between 0 and 1
13747  * @y_align: the vertical alignment, between 0 and 1
13748  * @x_fill: whether the actor should fill horizontally
13749  * @y_fill: whether the actor should fill vertically
13750  * @flags: allocation flags to be passed to clutter_actor_allocate()
13751  *
13752  * Allocates @self by taking into consideration the available allocation
13753  * area; an alignment factor on either axis; and whether the actor should
13754  * fill the allocation on either axis.
13755  *
13756  * The @box should contain the available allocation width and height;
13757  * if the x1 and y1 members of #ClutterActorBox are not set to 0, the
13758  * allocation will be offset by their value.
13759  *
13760  * This function takes into consideration the geometry request specified by
13761  * the #ClutterActor:request-mode property, and the text direction.
13762  *
13763  * This function is useful for fluid layout managers, like #ClutterBinLayout
13764  * or #ClutterTableLayout
13765  *
13766  * Since: 1.4
13767  */
13768 void
13769 clutter_actor_allocate_align_fill (ClutterActor           *self,
13770                                    const ClutterActorBox  *box,
13771                                    gdouble                 x_align,
13772                                    gdouble                 y_align,
13773                                    gboolean                x_fill,
13774                                    gboolean                y_fill,
13775                                    ClutterAllocationFlags  flags)
13776 {
13777   ClutterActorPrivate *priv;
13778   ClutterActorBox allocation = { 0, };
13779   gfloat x_offset, y_offset;
13780   gfloat available_width, available_height;
13781   gfloat child_width, child_height;
13782
13783   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13784   g_return_if_fail (box != NULL);
13785   g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
13786   g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
13787
13788   priv = self->priv;
13789
13790   clutter_actor_box_get_origin (box, &x_offset, &y_offset);
13791   clutter_actor_box_get_size (box, &available_width, &available_height);
13792
13793   if (available_width < 0)
13794     available_width = 0;
13795
13796   if (available_height < 0)
13797     available_height = 0;
13798
13799   if (x_fill)
13800     {
13801       allocation.x1 = x_offset;
13802       allocation.x2 = allocation.x1 + available_width;
13803     }
13804
13805   if (y_fill)
13806     {
13807       allocation.y1 = y_offset;
13808       allocation.y2 = allocation.y1 + available_height;
13809     }
13810
13811   /* if we are filling horizontally and vertically then we're done */
13812   if (x_fill && y_fill)
13813     goto out;
13814
13815   child_width = child_height = 0.0f;
13816
13817   if (priv->request_mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
13818     {
13819       gfloat min_width, natural_width;
13820       gfloat min_height, natural_height;
13821
13822       clutter_actor_get_preferred_width (self, available_height,
13823                                          &min_width,
13824                                          &natural_width);
13825
13826       child_width = CLAMP (natural_width, min_width, available_width);
13827
13828       if (!y_fill)
13829         {
13830           clutter_actor_get_preferred_height (self, child_width,
13831                                               &min_height,
13832                                               &natural_height);
13833
13834           child_height = CLAMP (natural_height, min_height, available_height);
13835         }
13836     }
13837   else
13838     {
13839       gfloat min_width, natural_width;
13840       gfloat min_height, natural_height;
13841
13842       clutter_actor_get_preferred_height (self, available_width,
13843                                           &min_height,
13844                                           &natural_height);
13845
13846       child_height = CLAMP (natural_height, min_height, available_height);
13847
13848       if (!x_fill)
13849         {
13850           clutter_actor_get_preferred_width (self, child_height,
13851                                              &min_width,
13852                                              &natural_width);
13853
13854           child_width = CLAMP (natural_width, min_width, available_width);
13855         }
13856     }
13857
13858   /* invert the horizontal alignment for RTL languages */
13859   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_RTL)
13860     x_align = 1.0 - x_align;
13861
13862   if (!x_fill)
13863     {
13864       allocation.x1 = x_offset
13865                     + ((available_width - child_width) * x_align);
13866       allocation.x2 = allocation.x1 + child_width;
13867     }
13868
13869   if (!y_fill)
13870     {
13871       allocation.y1 = y_offset
13872                     + ((available_height - child_height) * y_align);
13873       allocation.y2 = allocation.y1 + child_height;
13874     }
13875
13876 out:
13877   clutter_actor_box_clamp_to_pixel (&allocation);
13878   clutter_actor_allocate (self, &allocation, flags);
13879 }
13880
13881 /**
13882  * clutter_actor_grab_key_focus:
13883  * @self: a #ClutterActor
13884  *
13885  * Sets the key focus of the #ClutterStage including @self
13886  * to this #ClutterActor.
13887  *
13888  * Since: 1.0
13889  */
13890 void
13891 clutter_actor_grab_key_focus (ClutterActor *self)
13892 {
13893   ClutterActor *stage;
13894
13895   g_return_if_fail (CLUTTER_IS_ACTOR (self));
13896
13897   stage = _clutter_actor_get_stage_internal (self);
13898   if (stage != NULL)
13899     clutter_stage_set_key_focus (CLUTTER_STAGE (stage), self);
13900 }
13901
13902 /**
13903  * clutter_actor_get_pango_context:
13904  * @self: a #ClutterActor
13905  *
13906  * Retrieves the #PangoContext for @self. The actor's #PangoContext
13907  * is already configured using the appropriate font map, resolution
13908  * and font options.
13909  *
13910  * Unlike clutter_actor_create_pango_context(), this context is owend
13911  * by the #ClutterActor and it will be updated each time the options
13912  * stored by the #ClutterBackend change.
13913  *
13914  * You can use the returned #PangoContext to create a #PangoLayout
13915  * and render text using cogl_pango_render_layout() to reuse the
13916  * glyphs cache also used by Clutter.
13917  *
13918  * Return value: (transfer none): the #PangoContext for a #ClutterActor.
13919  *   The returned #PangoContext is owned by the actor and should not be
13920  *   unreferenced by the application code
13921  *
13922  * Since: 1.0
13923  */
13924 PangoContext *
13925 clutter_actor_get_pango_context (ClutterActor *self)
13926 {
13927   ClutterActorPrivate *priv;
13928
13929   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13930
13931   priv = self->priv;
13932
13933   if (priv->pango_context != NULL)
13934     return priv->pango_context;
13935
13936   priv->pango_context = _clutter_context_get_pango_context ();
13937   g_object_ref (priv->pango_context);
13938
13939   return priv->pango_context;
13940 }
13941
13942 /**
13943  * clutter_actor_create_pango_context:
13944  * @self: a #ClutterActor
13945  *
13946  * Creates a #PangoContext for the given actor. The #PangoContext
13947  * is already configured using the appropriate font map, resolution
13948  * and font options.
13949  *
13950  * See also clutter_actor_get_pango_context().
13951  *
13952  * Return value: (transfer full): the newly created #PangoContext.
13953  *   Use g_object_unref() on the returned value to deallocate its
13954  *   resources
13955  *
13956  * Since: 1.0
13957  */
13958 PangoContext *
13959 clutter_actor_create_pango_context (ClutterActor *self)
13960 {
13961   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13962
13963   return _clutter_context_create_pango_context ();
13964 }
13965
13966 /**
13967  * clutter_actor_create_pango_layout:
13968  * @self: a #ClutterActor
13969  * @text: (allow-none) the text to set on the #PangoLayout, or %NULL
13970  *
13971  * Creates a new #PangoLayout from the same #PangoContext used
13972  * by the #ClutterActor. The #PangoLayout is already configured
13973  * with the font map, resolution and font options, and the
13974  * given @text.
13975  *
13976  * If you want to keep around a #PangoLayout created by this
13977  * function you will have to connect to the #ClutterBackend::font-changed
13978  * and #ClutterBackend::resolution-changed signals, and call
13979  * pango_layout_context_changed() in response to them.
13980  *
13981  * Return value: (transfer full): the newly created #PangoLayout.
13982  *   Use g_object_unref() when done
13983  *
13984  * Since: 1.0
13985  */
13986 PangoLayout *
13987 clutter_actor_create_pango_layout (ClutterActor *self,
13988                                    const gchar  *text)
13989 {
13990   PangoContext *context;
13991   PangoLayout *layout;
13992
13993   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
13994
13995   context = clutter_actor_get_pango_context (self);
13996   layout = pango_layout_new (context);
13997
13998   if (text)
13999     pango_layout_set_text (layout, text, -1);
14000
14001   return layout;
14002 }
14003
14004 /* Allows overriding the calculated paint opacity. Used by ClutterClone and
14005  * ClutterOffscreenEffect.
14006  */
14007 void
14008 _clutter_actor_set_opacity_override (ClutterActor *self,
14009                                      gint          opacity)
14010 {
14011   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14012
14013   self->priv->opacity_override = opacity;
14014 }
14015
14016 gint
14017 _clutter_actor_get_opacity_override (ClutterActor *self)
14018 {
14019   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), -1);
14020
14021   return self->priv->opacity_override;
14022 }
14023
14024 /* Allows you to disable applying the actors model view transform during
14025  * a paint. Used by ClutterClone. */
14026 void
14027 _clutter_actor_set_enable_model_view_transform (ClutterActor *self,
14028                                                 gboolean      enable)
14029 {
14030   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14031
14032   self->priv->enable_model_view_transform = enable;
14033 }
14034
14035 void
14036 _clutter_actor_set_enable_paint_unmapped (ClutterActor *self,
14037                                           gboolean      enable)
14038 {
14039   ClutterActorPrivate *priv;
14040
14041   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14042
14043   priv = self->priv;
14044
14045   priv->enable_paint_unmapped = enable;
14046
14047   if (priv->enable_paint_unmapped)
14048     {
14049       /* Make sure that the parents of the widget are realized first;
14050        * otherwise checks in clutter_actor_update_map_state() will
14051        * fail.
14052        */
14053       clutter_actor_realize (self);
14054
14055       clutter_actor_update_map_state (self, MAP_STATE_MAKE_MAPPED);
14056     }
14057   else
14058     {
14059       clutter_actor_update_map_state (self, MAP_STATE_MAKE_UNMAPPED);
14060     }
14061 }
14062
14063 static void
14064 clutter_anchor_coord_get_units (ClutterActor      *self,
14065                                 const AnchorCoord *coord,
14066                                 gfloat            *x,
14067                                 gfloat            *y,
14068                                 gfloat            *z)
14069 {
14070   if (coord->is_fractional)
14071     {
14072       gfloat actor_width, actor_height;
14073
14074       clutter_actor_get_size (self, &actor_width, &actor_height);
14075
14076       if (x)
14077         *x = actor_width * coord->v.fraction.x;
14078
14079       if (y)
14080         *y = actor_height * coord->v.fraction.y;
14081
14082       if (z)
14083         *z = 0;
14084     }
14085   else
14086     {
14087       if (x)
14088         *x = coord->v.units.x;
14089
14090       if (y)
14091         *y = coord->v.units.y;
14092
14093       if (z)
14094         *z = coord->v.units.z;
14095     }
14096 }
14097
14098 static void
14099 clutter_anchor_coord_set_units (AnchorCoord *coord,
14100                                 gfloat       x,
14101                                 gfloat       y,
14102                                 gfloat       z)
14103 {
14104   coord->is_fractional = FALSE;
14105   coord->v.units.x = x;
14106   coord->v.units.y = y;
14107   coord->v.units.z = z;
14108 }
14109
14110 static ClutterGravity
14111 clutter_anchor_coord_get_gravity (const AnchorCoord *coord)
14112 {
14113   if (coord->is_fractional)
14114     {
14115       if (coord->v.fraction.x == 0.0)
14116         {
14117           if (coord->v.fraction.y == 0.0)
14118             return CLUTTER_GRAVITY_NORTH_WEST;
14119           else if (coord->v.fraction.y == 0.5)
14120             return CLUTTER_GRAVITY_WEST;
14121           else if (coord->v.fraction.y == 1.0)
14122             return CLUTTER_GRAVITY_SOUTH_WEST;
14123           else
14124             return CLUTTER_GRAVITY_NONE;
14125         }
14126       else if (coord->v.fraction.x == 0.5)
14127         {
14128           if (coord->v.fraction.y == 0.0)
14129             return CLUTTER_GRAVITY_NORTH;
14130           else if (coord->v.fraction.y == 0.5)
14131             return CLUTTER_GRAVITY_CENTER;
14132           else if (coord->v.fraction.y == 1.0)
14133             return CLUTTER_GRAVITY_SOUTH;
14134           else
14135             return CLUTTER_GRAVITY_NONE;
14136         }
14137       else if (coord->v.fraction.x == 1.0)
14138         {
14139           if (coord->v.fraction.y == 0.0)
14140             return CLUTTER_GRAVITY_NORTH_EAST;
14141           else if (coord->v.fraction.y == 0.5)
14142             return CLUTTER_GRAVITY_EAST;
14143           else if (coord->v.fraction.y == 1.0)
14144             return CLUTTER_GRAVITY_SOUTH_EAST;
14145           else
14146             return CLUTTER_GRAVITY_NONE;
14147         }
14148       else
14149         return CLUTTER_GRAVITY_NONE;
14150     }
14151   else
14152     return CLUTTER_GRAVITY_NONE;
14153 }
14154
14155 static void
14156 clutter_anchor_coord_set_gravity (AnchorCoord    *coord,
14157                                   ClutterGravity  gravity)
14158 {
14159   switch (gravity)
14160     {
14161     case CLUTTER_GRAVITY_NORTH:
14162       coord->v.fraction.x = 0.5;
14163       coord->v.fraction.y = 0.0;
14164       break;
14165
14166     case CLUTTER_GRAVITY_NORTH_EAST:
14167       coord->v.fraction.x = 1.0;
14168       coord->v.fraction.y = 0.0;
14169       break;
14170
14171     case CLUTTER_GRAVITY_EAST:
14172       coord->v.fraction.x = 1.0;
14173       coord->v.fraction.y = 0.5;
14174       break;
14175
14176     case CLUTTER_GRAVITY_SOUTH_EAST:
14177       coord->v.fraction.x = 1.0;
14178       coord->v.fraction.y = 1.0;
14179       break;
14180
14181     case CLUTTER_GRAVITY_SOUTH:
14182       coord->v.fraction.x = 0.5;
14183       coord->v.fraction.y = 1.0;
14184       break;
14185
14186     case CLUTTER_GRAVITY_SOUTH_WEST:
14187       coord->v.fraction.x = 0.0;
14188       coord->v.fraction.y = 1.0;
14189       break;
14190
14191     case CLUTTER_GRAVITY_WEST:
14192       coord->v.fraction.x = 0.0;
14193       coord->v.fraction.y = 0.5;
14194       break;
14195
14196     case CLUTTER_GRAVITY_NORTH_WEST:
14197       coord->v.fraction.x = 0.0;
14198       coord->v.fraction.y = 0.0;
14199       break;
14200
14201     case CLUTTER_GRAVITY_CENTER:
14202       coord->v.fraction.x = 0.5;
14203       coord->v.fraction.y = 0.5;
14204       break;
14205
14206     default:
14207       coord->v.fraction.x = 0.0;
14208       coord->v.fraction.y = 0.0;
14209       break;
14210     }
14211
14212   coord->is_fractional = TRUE;
14213 }
14214
14215 static gboolean
14216 clutter_anchor_coord_is_zero (const AnchorCoord *coord)
14217 {
14218   if (coord->is_fractional)
14219     return coord->v.fraction.x == 0.0 && coord->v.fraction.y == 0.0;
14220   else
14221     return (coord->v.units.x == 0.0
14222             && coord->v.units.y == 0.0
14223             && coord->v.units.z == 0.0);
14224 }
14225
14226 /**
14227  * clutter_actor_get_flags:
14228  * @self: a #ClutterActor
14229  *
14230  * Retrieves the flags set on @self
14231  *
14232  * Return value: a bitwise or of #ClutterActorFlags or 0
14233  *
14234  * Since: 1.0
14235  */
14236 ClutterActorFlags
14237 clutter_actor_get_flags (ClutterActor *self)
14238 {
14239   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
14240
14241   return self->flags;
14242 }
14243
14244 /**
14245  * clutter_actor_set_flags:
14246  * @self: a #ClutterActor
14247  * @flags: the flags to set
14248  *
14249  * Sets @flags on @self
14250  *
14251  * This function will emit notifications for the changed properties
14252  *
14253  * Since: 1.0
14254  */
14255 void
14256 clutter_actor_set_flags (ClutterActor      *self,
14257                          ClutterActorFlags  flags)
14258 {
14259   ClutterActorFlags old_flags;
14260   GObject *obj;
14261   gboolean was_reactive_set, reactive_set;
14262   gboolean was_realized_set, realized_set;
14263   gboolean was_mapped_set, mapped_set;
14264   gboolean was_visible_set, visible_set;
14265
14266   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14267
14268   if (self->flags == flags)
14269     return;
14270
14271   obj = G_OBJECT (self);
14272   g_object_ref (obj);
14273   g_object_freeze_notify (obj);
14274
14275   old_flags = self->flags;
14276
14277   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14278   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14279   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14280   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14281
14282   self->flags |= flags;
14283
14284   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14285   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14286   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14287   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14288
14289   if (reactive_set != was_reactive_set)
14290     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14291
14292   if (realized_set != was_realized_set)
14293     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14294
14295   if (mapped_set != was_mapped_set)
14296     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14297
14298   if (visible_set != was_visible_set)
14299     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14300
14301   g_object_thaw_notify (obj);
14302   g_object_unref (obj);
14303 }
14304
14305 /**
14306  * clutter_actor_unset_flags:
14307  * @self: a #ClutterActor
14308  * @flags: the flags to unset
14309  *
14310  * Unsets @flags on @self
14311  *
14312  * This function will emit notifications for the changed properties
14313  *
14314  * Since: 1.0
14315  */
14316 void
14317 clutter_actor_unset_flags (ClutterActor      *self,
14318                            ClutterActorFlags  flags)
14319 {
14320   ClutterActorFlags old_flags;
14321   GObject *obj;
14322   gboolean was_reactive_set, reactive_set;
14323   gboolean was_realized_set, realized_set;
14324   gboolean was_mapped_set, mapped_set;
14325   gboolean was_visible_set, visible_set;
14326
14327   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14328
14329   obj = G_OBJECT (self);
14330   g_object_freeze_notify (obj);
14331
14332   old_flags = self->flags;
14333
14334   was_reactive_set = ((old_flags & CLUTTER_ACTOR_REACTIVE) != 0);
14335   was_realized_set = ((old_flags & CLUTTER_ACTOR_REALIZED) != 0);
14336   was_mapped_set   = ((old_flags & CLUTTER_ACTOR_MAPPED)   != 0);
14337   was_visible_set  = ((old_flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14338
14339   self->flags &= ~flags;
14340
14341   if (self->flags == old_flags)
14342     return;
14343
14344   reactive_set = ((self->flags & CLUTTER_ACTOR_REACTIVE) != 0);
14345   realized_set = ((self->flags & CLUTTER_ACTOR_REALIZED) != 0);
14346   mapped_set   = ((self->flags & CLUTTER_ACTOR_MAPPED)   != 0);
14347   visible_set  = ((self->flags & CLUTTER_ACTOR_VISIBLE)  != 0);
14348
14349   if (reactive_set != was_reactive_set)
14350     g_object_notify_by_pspec (obj, obj_props[PROP_REACTIVE]);
14351
14352   if (realized_set != was_realized_set)
14353     g_object_notify_by_pspec (obj, obj_props[PROP_REALIZED]);
14354
14355   if (mapped_set != was_mapped_set)
14356     g_object_notify_by_pspec (obj, obj_props[PROP_MAPPED]);
14357
14358   if (visible_set != was_visible_set)
14359     g_object_notify_by_pspec (obj, obj_props[PROP_VISIBLE]);
14360
14361   g_object_thaw_notify (obj);
14362 }
14363
14364 /**
14365  * clutter_actor_get_transformation_matrix:
14366  * @self: a #ClutterActor
14367  * @matrix: (out caller-allocates): the return location for a #CoglMatrix
14368  *
14369  * Retrieves the transformations applied to @self relative to its
14370  * parent.
14371  *
14372  * Since: 1.0
14373  */
14374 void
14375 clutter_actor_get_transformation_matrix (ClutterActor *self,
14376                                          CoglMatrix   *matrix)
14377 {
14378   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14379
14380   cogl_matrix_init_identity (matrix);
14381
14382   _clutter_actor_apply_modelview_transform (self, matrix);
14383 }
14384
14385 void
14386 _clutter_actor_set_in_clone_paint (ClutterActor *self,
14387                                    gboolean      is_in_clone_paint)
14388 {
14389   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14390   self->priv->in_clone_paint = is_in_clone_paint;
14391 }
14392
14393 /**
14394  * clutter_actor_is_in_clone_paint:
14395  * @self: a #ClutterActor
14396  *
14397  * Checks whether @self is being currently painted by a #ClutterClone
14398  *
14399  * This function is useful only inside the ::paint virtual function
14400  * implementations or within handlers for the #ClutterActor::paint
14401  * signal
14402  *
14403  * This function should not be used by applications
14404  *
14405  * Return value: %TRUE if the #ClutterActor is currently being painted
14406  *   by a #ClutterClone, and %FALSE otherwise
14407  *
14408  * Since: 1.0
14409  */
14410 gboolean
14411 clutter_actor_is_in_clone_paint (ClutterActor *self)
14412 {
14413   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14414
14415   return self->priv->in_clone_paint;
14416 }
14417
14418 static gboolean
14419 set_direction_recursive (ClutterActor *actor,
14420                          gpointer      user_data)
14421 {
14422   ClutterTextDirection text_dir = GPOINTER_TO_INT (user_data);
14423
14424   clutter_actor_set_text_direction (actor, text_dir);
14425
14426   return TRUE;
14427 }
14428
14429 /**
14430  * clutter_actor_set_text_direction:
14431  * @self: a #ClutterActor
14432  * @text_dir: the text direction for @self
14433  *
14434  * Sets the #ClutterTextDirection for an actor
14435  *
14436  * The passed text direction must not be %CLUTTER_TEXT_DIRECTION_DEFAULT
14437  *
14438  * If @self implements #ClutterContainer then this function will recurse
14439  * inside all the children of @self (including the internal ones).
14440  *
14441  * Composite actors not implementing #ClutterContainer, or actors requiring
14442  * special handling when the text direction changes, should connect to
14443  * the #GObject::notify signal for the #ClutterActor:text-direction property
14444  *
14445  * Since: 1.2
14446  */
14447 void
14448 clutter_actor_set_text_direction (ClutterActor         *self,
14449                                   ClutterTextDirection  text_dir)
14450 {
14451   ClutterActorPrivate *priv;
14452
14453   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14454   g_return_if_fail (text_dir != CLUTTER_TEXT_DIRECTION_DEFAULT);
14455
14456   priv = self->priv;
14457
14458   if (priv->text_direction != text_dir)
14459     {
14460       priv->text_direction = text_dir;
14461
14462       /* we need to emit the notify::text-direction first, so that
14463        * the sub-classes can catch that and do specific handling of
14464        * the text direction; see clutter_text_direction_changed_cb()
14465        * inside clutter-text.c
14466        */
14467       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT_DIRECTION]);
14468
14469       _clutter_actor_foreach_child (self, set_direction_recursive,
14470                                     GINT_TO_POINTER (text_dir));
14471
14472       clutter_actor_queue_relayout (self);
14473     }
14474 }
14475
14476 void
14477 _clutter_actor_set_has_pointer (ClutterActor *self,
14478                                 gboolean      has_pointer)
14479 {
14480   ClutterActorPrivate *priv = self->priv;
14481
14482   if (priv->has_pointer != has_pointer)
14483     {
14484       priv->has_pointer = has_pointer;
14485
14486       g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_HAS_POINTER]);
14487     }
14488 }
14489
14490 /**
14491  * clutter_actor_get_text_direction:
14492  * @self: a #ClutterActor
14493  *
14494  * Retrieves the value set using clutter_actor_set_text_direction()
14495  *
14496  * If no text direction has been previously set, the default text
14497  * direction, as returned by clutter_get_default_text_direction(), will
14498  * be returned instead
14499  *
14500  * Return value: the #ClutterTextDirection for the actor
14501  *
14502  * Since: 1.2
14503  */
14504 ClutterTextDirection
14505 clutter_actor_get_text_direction (ClutterActor *self)
14506 {
14507   ClutterActorPrivate *priv;
14508
14509   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
14510                         CLUTTER_TEXT_DIRECTION_LTR);
14511
14512   priv = self->priv;
14513
14514   /* if no direction has been set yet use the default */
14515   if (priv->text_direction == CLUTTER_TEXT_DIRECTION_DEFAULT)
14516     priv->text_direction = clutter_get_default_text_direction ();
14517
14518   return priv->text_direction;
14519 }
14520
14521 /**
14522  * clutter_actor_push_internal:
14523  * @self: a #ClutterActor
14524  *
14525  * Should be used by actors implementing the #ClutterContainer and with
14526  * internal children added through clutter_actor_set_parent(), for instance:
14527  *
14528  * |[
14529  *   static void
14530  *   my_actor_init (MyActor *self)
14531  *   {
14532  *     self->priv = SELF_ACTOR_GET_PRIVATE (self);
14533  *
14534  *     clutter_actor_push_internal (CLUTTER_ACTOR (self));
14535  *
14536  *     /&ast; calling clutter_actor_set_parent() now will result in
14537  *      &ast; the internal flag being set on a child of MyActor
14538  *      &ast;/
14539  *
14540  *     /&ast; internal child - a background texture &ast;/
14541  *     self->priv->background_tex = clutter_texture_new ();
14542  *     clutter_actor_set_parent (self->priv->background_tex,
14543  *                               CLUTTER_ACTOR (self));
14544  *
14545  *     /&ast; internal child - a label &ast;/
14546  *     self->priv->label = clutter_text_new ();
14547  *     clutter_actor_set_parent (self->priv->label,
14548  *                               CLUTTER_ACTOR (self));
14549  *
14550  *     clutter_actor_pop_internal (CLUTTER_ACTOR (self));
14551  *
14552  *     /&ast; calling clutter_actor_set_parent() now will not result in
14553  *      &ast; the internal flag being set on a child of MyActor
14554  *      &ast;/
14555  *   }
14556  * ]|
14557  *
14558  * This function will be used by Clutter to toggle an "internal child"
14559  * flag whenever clutter_actor_set_parent() is called; internal children
14560  * are handled differently by Clutter, specifically when destroying their
14561  * parent.
14562  *
14563  * Call clutter_actor_pop_internal() when you finished adding internal
14564  * children.
14565  *
14566  * Nested calls to clutter_actor_push_internal() are allowed, but each
14567  * one must by followed by a clutter_actor_pop_internal() call.
14568  *
14569  * Since: 1.2
14570  *
14571  * Deprecated: 1.10: All children of an actor are accessible through
14572  *   the #ClutterActor API, and #ClutterActor implements the
14573  *   #ClutterContainer interface, so this function is only useful
14574  *   for legacy containers overriding the default implementation.
14575  */
14576 void
14577 clutter_actor_push_internal (ClutterActor *self)
14578 {
14579   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14580
14581   self->priv->internal_child += 1;
14582 }
14583
14584 /**
14585  * clutter_actor_pop_internal:
14586  * @self: a #ClutterActor
14587  *
14588  * Disables the effects of clutter_actor_push_internal().
14589  *
14590  * Since: 1.2
14591  *
14592  * Deprecated: 1.10: All children of an actor are accessible through
14593  *   the #ClutterActor API. This function is only useful for legacy
14594  *   containers overriding the default implementation of the
14595  *   #ClutterContainer interface.
14596  */
14597 void
14598 clutter_actor_pop_internal (ClutterActor *self)
14599 {
14600   ClutterActorPrivate *priv;
14601
14602   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14603
14604   priv = self->priv;
14605
14606   if (priv->internal_child == 0)
14607     {
14608       g_warning ("Mismatched %s: you need to call "
14609                  "clutter_actor_push_composite() at least once before "
14610                  "calling this function", G_STRFUNC);
14611       return;
14612     }
14613
14614   priv->internal_child -= 1;
14615 }
14616
14617 /**
14618  * clutter_actor_has_pointer:
14619  * @self: a #ClutterActor
14620  *
14621  * Checks whether an actor contains the pointer of a
14622  * #ClutterInputDevice
14623  *
14624  * Return value: %TRUE if the actor contains the pointer, and
14625  *   %FALSE otherwise
14626  *
14627  * Since: 1.2
14628  */
14629 gboolean
14630 clutter_actor_has_pointer (ClutterActor *self)
14631 {
14632   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14633
14634   return self->priv->has_pointer;
14635 }
14636
14637 /* XXX: This is a workaround for not being able to break the ABI of
14638  * the QUEUE_REDRAW signal. It is an out-of-band argument.  See
14639  * clutter_actor_queue_clipped_redraw() for details.
14640  */
14641 ClutterPaintVolume *
14642 _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
14643 {
14644   return g_object_get_data (G_OBJECT (self),
14645                             "-clutter-actor-queue-redraw-clip");
14646 }
14647
14648 void
14649 _clutter_actor_set_queue_redraw_clip (ClutterActor       *self,
14650                                       ClutterPaintVolume *clip)
14651 {
14652   g_object_set_data (G_OBJECT (self),
14653                      "-clutter-actor-queue-redraw-clip",
14654                      clip);
14655 }
14656
14657 /**
14658  * clutter_actor_has_allocation:
14659  * @self: a #ClutterActor
14660  *
14661  * Checks if the actor has an up-to-date allocation assigned to
14662  * it. This means that the actor should have an allocation: it's
14663  * visible and has a parent. It also means that there is no
14664  * outstanding relayout request in progress for the actor or its
14665  * children (There might be other outstanding layout requests in
14666  * progress that will cause the actor to get a new allocation
14667  * when the stage is laid out, however).
14668  *
14669  * If this function returns %FALSE, then the actor will normally
14670  * be allocated before it is next drawn on the screen.
14671  *
14672  * Return value: %TRUE if the actor has an up-to-date allocation
14673  *
14674  * Since: 1.4
14675  */
14676 gboolean
14677 clutter_actor_has_allocation (ClutterActor *self)
14678 {
14679   ClutterActorPrivate *priv;
14680
14681   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
14682
14683   priv = self->priv;
14684
14685   return priv->parent != NULL &&
14686          CLUTTER_ACTOR_IS_VISIBLE (self) &&
14687          !priv->needs_allocation;
14688 }
14689
14690 /**
14691  * clutter_actor_add_action:
14692  * @self: a #ClutterActor
14693  * @action: a #ClutterAction
14694  *
14695  * Adds @action to the list of actions applied to @self
14696  *
14697  * A #ClutterAction can only belong to one actor at a time
14698  *
14699  * The #ClutterActor will hold a reference on @action until either
14700  * clutter_actor_remove_action() or clutter_actor_clear_actions()
14701  * is called
14702  *
14703  * Since: 1.4
14704  */
14705 void
14706 clutter_actor_add_action (ClutterActor  *self,
14707                           ClutterAction *action)
14708 {
14709   ClutterActorPrivate *priv;
14710
14711   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14712   g_return_if_fail (CLUTTER_IS_ACTION (action));
14713
14714   priv = self->priv;
14715
14716   if (priv->actions == NULL)
14717     {
14718       priv->actions = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14719       priv->actions->actor = self;
14720     }
14721
14722   _clutter_meta_group_add_meta (priv->actions, CLUTTER_ACTOR_META (action));
14723
14724   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14725 }
14726
14727 /**
14728  * clutter_actor_add_action_with_name:
14729  * @self: a #ClutterActor
14730  * @name: the name to set on the action
14731  * @action: a #ClutterAction
14732  *
14733  * A convenience function for setting the name of a #ClutterAction
14734  * while adding it to the list of actions applied to @self
14735  *
14736  * This function is the logical equivalent of:
14737  *
14738  * |[
14739  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14740  *   clutter_actor_add_action (self, action);
14741  * ]|
14742  *
14743  * Since: 1.4
14744  */
14745 void
14746 clutter_actor_add_action_with_name (ClutterActor  *self,
14747                                     const gchar   *name,
14748                                     ClutterAction *action)
14749 {
14750   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14751   g_return_if_fail (name != NULL);
14752   g_return_if_fail (CLUTTER_IS_ACTION (action));
14753
14754   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (action), name);
14755   clutter_actor_add_action (self, action);
14756 }
14757
14758 /**
14759  * clutter_actor_remove_action:
14760  * @self: a #ClutterActor
14761  * @action: a #ClutterAction
14762  *
14763  * Removes @action from the list of actions applied to @self
14764  *
14765  * The reference held by @self on the #ClutterAction will be released
14766  *
14767  * Since: 1.4
14768  */
14769 void
14770 clutter_actor_remove_action (ClutterActor  *self,
14771                              ClutterAction *action)
14772 {
14773   ClutterActorPrivate *priv;
14774
14775   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14776   g_return_if_fail (CLUTTER_IS_ACTION (action));
14777
14778   priv = self->priv;
14779
14780   if (priv->actions == NULL)
14781     return;
14782
14783   _clutter_meta_group_remove_meta (priv->actions, CLUTTER_ACTOR_META (action));
14784
14785   if (_clutter_meta_group_peek_metas (priv->actions) == NULL)
14786     g_clear_object (&priv->actions);
14787
14788   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14789 }
14790
14791 /**
14792  * clutter_actor_remove_action_by_name:
14793  * @self: a #ClutterActor
14794  * @name: the name of the action to remove
14795  *
14796  * Removes the #ClutterAction with the given name from the list
14797  * of actions applied to @self
14798  *
14799  * Since: 1.4
14800  */
14801 void
14802 clutter_actor_remove_action_by_name (ClutterActor *self,
14803                                      const gchar  *name)
14804 {
14805   ClutterActorPrivate *priv;
14806   ClutterActorMeta *meta;
14807
14808   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14809   g_return_if_fail (name != NULL);
14810
14811   priv = self->priv;
14812
14813   if (priv->actions == NULL)
14814     return;
14815
14816   meta = _clutter_meta_group_get_meta (priv->actions, name);
14817   if (meta == NULL)
14818     return;
14819
14820   _clutter_meta_group_remove_meta (priv->actions, meta);
14821
14822   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIONS]);
14823 }
14824
14825 /**
14826  * clutter_actor_get_actions:
14827  * @self: a #ClutterActor
14828  *
14829  * Retrieves the list of actions applied to @self
14830  *
14831  * Return value: (transfer container) (element-type Clutter.Action): a copy
14832  *   of the list of #ClutterAction<!-- -->s. The contents of the list are
14833  *   owned by the #ClutterActor. Use g_list_free() to free the resources
14834  *   allocated by the returned #GList
14835  *
14836  * Since: 1.4
14837  */
14838 GList *
14839 clutter_actor_get_actions (ClutterActor *self)
14840 {
14841   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14842
14843   if (self->priv->actions == NULL)
14844     return NULL;
14845
14846   return _clutter_meta_group_get_metas_no_internal (self->priv->actions);
14847 }
14848
14849 /**
14850  * clutter_actor_get_action:
14851  * @self: a #ClutterActor
14852  * @name: the name of the action to retrieve
14853  *
14854  * Retrieves the #ClutterAction with the given name in the list
14855  * of actions applied to @self
14856  *
14857  * Return value: (transfer none): a #ClutterAction for the given
14858  *   name, or %NULL. The returned #ClutterAction is owned by the
14859  *   actor and it should not be unreferenced directly
14860  *
14861  * Since: 1.4
14862  */
14863 ClutterAction *
14864 clutter_actor_get_action (ClutterActor *self,
14865                           const gchar  *name)
14866 {
14867   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
14868   g_return_val_if_fail (name != NULL, NULL);
14869
14870   if (self->priv->actions == NULL)
14871     return NULL;
14872
14873   return CLUTTER_ACTION (_clutter_meta_group_get_meta (self->priv->actions, name));
14874 }
14875
14876 /**
14877  * clutter_actor_clear_actions:
14878  * @self: a #ClutterActor
14879  *
14880  * Clears the list of actions applied to @self
14881  *
14882  * Since: 1.4
14883  */
14884 void
14885 clutter_actor_clear_actions (ClutterActor *self)
14886 {
14887   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14888
14889   if (self->priv->actions == NULL)
14890     return;
14891
14892   _clutter_meta_group_clear_metas_no_internal (self->priv->actions);
14893 }
14894
14895 /**
14896  * clutter_actor_add_constraint:
14897  * @self: a #ClutterActor
14898  * @constraint: a #ClutterConstraint
14899  *
14900  * Adds @constraint to the list of #ClutterConstraint<!-- -->s applied
14901  * to @self
14902  *
14903  * The #ClutterActor will hold a reference on the @constraint until
14904  * either clutter_actor_remove_constraint() or
14905  * clutter_actor_clear_constraints() is called.
14906  *
14907  * Since: 1.4
14908  */
14909 void
14910 clutter_actor_add_constraint (ClutterActor      *self,
14911                               ClutterConstraint *constraint)
14912 {
14913   ClutterActorPrivate *priv;
14914
14915   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14916   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14917
14918   priv = self->priv;
14919
14920   if (priv->constraints == NULL)
14921     {
14922       priv->constraints = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
14923       priv->constraints->actor = self;
14924     }
14925
14926   _clutter_meta_group_add_meta (priv->constraints,
14927                                 CLUTTER_ACTOR_META (constraint));
14928   clutter_actor_queue_relayout (self);
14929
14930   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONSTRAINTS]);
14931 }
14932
14933 /**
14934  * clutter_actor_add_constraint_with_name:
14935  * @self: a #ClutterActor
14936  * @name: the name to set on the constraint
14937  * @constraint: a #ClutterConstraint
14938  *
14939  * A convenience function for setting the name of a #ClutterConstraint
14940  * while adding it to the list of constraints applied to @self
14941  *
14942  * This function is the logical equivalent of:
14943  *
14944  * |[
14945  *   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14946  *   clutter_actor_add_constraint (self, constraint);
14947  * ]|
14948  *
14949  * Since: 1.4
14950  */
14951 void
14952 clutter_actor_add_constraint_with_name (ClutterActor      *self,
14953                                         const gchar       *name,
14954                                         ClutterConstraint *constraint)
14955 {
14956   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14957   g_return_if_fail (name != NULL);
14958   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14959
14960   clutter_actor_meta_set_name (CLUTTER_ACTOR_META (constraint), name);
14961   clutter_actor_add_constraint (self, constraint);
14962 }
14963
14964 /**
14965  * clutter_actor_remove_constraint:
14966  * @self: a #ClutterActor
14967  * @constraint: a #ClutterConstraint
14968  *
14969  * Removes @constraint from the list of constraints applied to @self
14970  *
14971  * The reference held by @self on the #ClutterConstraint will be released
14972  *
14973  * Since: 1.4
14974  */
14975 void
14976 clutter_actor_remove_constraint (ClutterActor      *self,
14977                                  ClutterConstraint *constraint)
14978 {
14979   ClutterActorPrivate *priv;
14980
14981   g_return_if_fail (CLUTTER_IS_ACTOR (self));
14982   g_return_if_fail (CLUTTER_IS_CONSTRAINT (constraint));
14983
14984   priv = self->priv;
14985
14986   if (priv->constraints == NULL)
14987     return;
14988
14989   _clutter_meta_group_remove_meta (priv->constraints,
14990                                    CLUTTER_ACTOR_META (constraint));
14991
14992   if (_clutter_meta_group_peek_metas (priv->constraints) == NULL)
14993     g_clear_object (&priv->constraints);
14994
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   ClutterTimeline *timeline = CLUTTER_TIMELINE (transition);
17066   ClutterActor *actor = clos->actor;
17067   ClutterAnimationInfo *info;
17068   gint n_repeats, cur_repeat;
17069
17070   info = _clutter_actor_get_animation_info (actor);
17071
17072   /* reset the caches used by animations */
17073   clutter_actor_store_content_box (actor, NULL);
17074
17075   /* ensure that we remove the transition only at the end
17076    * of its run; we emit ::completed for every repeat
17077    */
17078   n_repeats = clutter_timeline_get_repeat_count (timeline);
17079   cur_repeat = clutter_timeline_get_current_repeat (timeline);
17080
17081   if (cur_repeat == n_repeats)
17082     {
17083       if (clutter_transition_get_remove_on_complete (transition))
17084         {
17085           /* we take a reference here because removing the closure
17086            * will release the reference on the transition, and we
17087            * want the transition to survive the signal emission;
17088            * the master clock will release the last reference at
17089            * the end of the frame processing.
17090            */
17091           g_object_ref (transition);
17092           g_hash_table_remove (info->transitions, clos->name);
17093         }
17094     }
17095
17096   /* if it's the last transition then we clean up */
17097   if (g_hash_table_size (info->transitions) == 0)
17098     {
17099       g_hash_table_unref (info->transitions);
17100       info->transitions = NULL;
17101
17102       CLUTTER_NOTE (ANIMATION, "Transitions for '%s' completed",
17103                     _clutter_actor_get_debug_name (actor));
17104
17105       g_signal_emit (actor, actor_signals[TRANSITIONS_COMPLETED], 0);
17106     }
17107 }
17108
17109 void
17110 _clutter_actor_update_transition (ClutterActor *actor,
17111                                   GParamSpec   *pspec,
17112                                   ...)
17113 {
17114   TransitionClosure *clos;
17115   ClutterTimeline *timeline;
17116   ClutterInterval *interval;
17117   const ClutterAnimationInfo *info;
17118   va_list var_args;
17119   GType ptype;
17120   GValue initial = G_VALUE_INIT;
17121   GValue final = G_VALUE_INIT;
17122   char *error = NULL;
17123
17124   info = _clutter_actor_get_animation_info_or_defaults (actor);
17125
17126   if (info->transitions == NULL)
17127     return;
17128
17129   clos = g_hash_table_lookup (info->transitions, pspec->name);
17130   if (clos == NULL)
17131     return;
17132
17133   timeline = CLUTTER_TIMELINE (clos->transition);
17134
17135   va_start (var_args, pspec);
17136
17137   ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17138
17139   g_value_init (&initial, ptype);
17140   clutter_animatable_get_initial_state (CLUTTER_ANIMATABLE (actor),
17141                                         pspec->name,
17142                                         &initial);
17143
17144   G_VALUE_COLLECT_INIT (&final, ptype, var_args, 0, &error);
17145   if (error != NULL)
17146     {
17147       g_critical ("%s: %s", G_STRLOC, error);
17148       g_free (error);
17149       goto out;
17150     }
17151
17152   interval = clutter_transition_get_interval (clos->transition);
17153   clutter_interval_set_initial_value (interval, &initial);
17154   clutter_interval_set_final_value (interval, &final);
17155
17156   /* if we're updating with an easing duration of zero milliseconds,
17157    * we just jump the timeline to the end and let it run its course
17158    */
17159   if (info->cur_state != NULL &&
17160       info->cur_state->easing_duration != 0)
17161     {
17162       guint cur_duration = clutter_timeline_get_duration (timeline);
17163       ClutterAnimationMode cur_mode =
17164         clutter_timeline_get_progress_mode (timeline);
17165
17166       if (cur_duration != info->cur_state->easing_duration)
17167         clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17168
17169       if (cur_mode != info->cur_state->easing_mode)
17170         clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17171
17172       clutter_timeline_rewind (timeline);
17173     }
17174   else
17175     {
17176       guint duration = clutter_timeline_get_duration (timeline);
17177
17178       clutter_timeline_advance (timeline, duration);
17179     }
17180
17181 out:
17182   g_value_unset (&initial);
17183   g_value_unset (&final);
17184
17185   va_end (var_args);
17186 }
17187
17188 /*< private >*
17189  * _clutter_actor_create_transition:
17190  * @actor: a #ClutterActor
17191  * @pspec: the property used for the transition
17192  * @...: initial and final state
17193  *
17194  * Creates a #ClutterTransition for the property represented by @pspec.
17195  *
17196  * Return value: a #ClutterTransition
17197  */
17198 ClutterTransition *
17199 _clutter_actor_create_transition (ClutterActor *actor,
17200                                   GParamSpec   *pspec,
17201                                   ...)
17202 {
17203   ClutterAnimationInfo *info;
17204   ClutterTransition *res = NULL;
17205   gboolean call_restore = FALSE;
17206   TransitionClosure *clos;
17207   va_list var_args;
17208
17209   info = _clutter_actor_get_animation_info (actor);
17210
17211   /* XXX - this will go away in 2.0
17212    *
17213    * if no state has been pushed, we assume that the easing state is
17214    * in "compatibility mode": all transitions have a duration of 0
17215    * msecs, which means that they happen immediately. in Clutter 2.0
17216    * this will turn into a g_assert(info->states != NULL), as every
17217    * actor will start with a predefined easing state
17218    */
17219   if (info->states == NULL)
17220     {
17221       clutter_actor_save_easing_state (actor);
17222       clutter_actor_set_easing_duration (actor, 0);
17223       call_restore = TRUE;
17224     }
17225
17226   if (info->transitions == NULL)
17227     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17228                                                NULL,
17229                                                transition_closure_free);
17230
17231   va_start (var_args, pspec);
17232
17233   clos = g_hash_table_lookup (info->transitions, pspec->name);
17234   if (clos == NULL)
17235     {
17236       ClutterInterval *interval;
17237       GValue initial = G_VALUE_INIT;
17238       GValue final = G_VALUE_INIT;
17239       GType ptype;
17240       char *error;
17241
17242       ptype = G_PARAM_SPEC_VALUE_TYPE (pspec);
17243
17244       G_VALUE_COLLECT_INIT (&initial, ptype,
17245                             var_args, 0,
17246                             &error);
17247       if (error != NULL)
17248         {
17249           g_critical ("%s: %s", G_STRLOC, error);
17250           g_free (error);
17251           goto out;
17252         }
17253
17254       G_VALUE_COLLECT_INIT (&final, ptype,
17255                             var_args, 0,
17256                             &error);
17257
17258       if (error != NULL)
17259         {
17260           g_critical ("%s: %s", G_STRLOC, error);
17261           g_value_unset (&initial);
17262           g_free (error);
17263           goto out;
17264         }
17265
17266       /* if the current easing state has a duration of 0, then we don't
17267        * bother to create the transition, and we just set the final value
17268        * directly on the actor; we don't go through the Animatable
17269        * interface because we know we got here through an animatable
17270        * property.
17271        */
17272       if (info->cur_state->easing_duration == 0)
17273         {
17274           clutter_actor_set_animatable_property (actor,
17275                                                  pspec->param_id,
17276                                                  &final,
17277                                                  pspec);
17278           g_value_unset (&initial);
17279           g_value_unset (&final);
17280
17281           goto out;
17282         }
17283
17284       interval = clutter_interval_new_with_values (ptype, &initial, &final);
17285
17286       g_value_unset (&initial);
17287       g_value_unset (&final);
17288
17289       res = clutter_property_transition_new (pspec->name);
17290
17291       clutter_transition_set_interval (res, interval);
17292       clutter_transition_set_remove_on_complete (res, TRUE);
17293
17294       /* this will start the transition as well */
17295       clutter_actor_add_transition (actor, pspec->name, res);
17296
17297       /* the actor now owns the transition */
17298       g_object_unref (res);
17299     }
17300   else
17301     res = clos->transition;
17302
17303 out:
17304   if (call_restore)
17305     clutter_actor_restore_easing_state (actor);
17306
17307   va_end (var_args);
17308
17309   return res;
17310 }
17311
17312 /**
17313  * clutter_actor_add_transition:
17314  * @self: a #ClutterActor
17315  * @name: the name of the transition to add
17316  * @transition: the #ClutterTransition to add
17317  *
17318  * Adds a @transition to the #ClutterActor's list of animations.
17319  *
17320  * The @name string is a per-actor unique identifier of the @transition: only
17321  * one #ClutterTransition can be associated to the specified @name.
17322  *
17323  * The @transition will be given the easing duration, mode, and delay
17324  * associated to the actor's current easing state; it is possible to modify
17325  * these values after calling clutter_actor_add_transition().
17326  *
17327  * The @transition will be started once added.
17328  *
17329  * This function will take a reference on the @transition.
17330  *
17331  * This function is usually called implicitly when modifying an animatable
17332  * property.
17333  *
17334  * Since: 1.10
17335  */
17336 void
17337 clutter_actor_add_transition (ClutterActor      *self,
17338                               const char        *name,
17339                               ClutterTransition *transition)
17340 {
17341   ClutterTimeline *timeline;
17342   TransitionClosure *clos;
17343   ClutterAnimationInfo *info;
17344
17345   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17346   g_return_if_fail (name != NULL);
17347   g_return_if_fail (CLUTTER_IS_TRANSITION (transition));
17348
17349   info = _clutter_actor_get_animation_info (self);
17350
17351   if (info->cur_state == NULL)
17352     {
17353       g_warning ("No easing state is defined for the actor '%s'; you "
17354                  "must call clutter_actor_save_easing_state() before "
17355                  "calling clutter_actor_add_transition().",
17356                  _clutter_actor_get_debug_name (self));
17357       return;
17358     }
17359
17360   if (info->transitions == NULL)
17361     info->transitions = g_hash_table_new_full (g_str_hash, g_str_equal,
17362                                                NULL,
17363                                                transition_closure_free);
17364
17365   if (g_hash_table_lookup (info->transitions, name) != NULL)
17366     {
17367       g_warning ("A transition with name '%s' already exists for "
17368                  "the actor '%s'",
17369                  name,
17370                  _clutter_actor_get_debug_name (self));
17371       return;
17372     }
17373
17374   clutter_transition_set_animatable (transition, CLUTTER_ANIMATABLE (self));
17375
17376   timeline = CLUTTER_TIMELINE (transition);
17377
17378   clutter_timeline_set_delay (timeline, info->cur_state->easing_delay);
17379   clutter_timeline_set_duration (timeline, info->cur_state->easing_duration);
17380   clutter_timeline_set_progress_mode (timeline, info->cur_state->easing_mode);
17381
17382   clos = g_slice_new (TransitionClosure);
17383   clos->actor = self;
17384   clos->transition = g_object_ref (transition);
17385   clos->name = g_strdup (name);
17386   clos->completed_id = g_signal_connect (timeline, "completed",
17387                                          G_CALLBACK (on_transition_completed),
17388                                          clos);
17389
17390   CLUTTER_NOTE (ANIMATION,
17391                 "Adding transition '%s' [%p] to actor '%s'",
17392                 clos->name,
17393                 clos->transition,
17394                 _clutter_actor_get_debug_name (self));
17395
17396   g_hash_table_insert (info->transitions, clos->name, clos);
17397   clutter_timeline_start (timeline);
17398 }
17399
17400 /**
17401  * clutter_actor_remove_transition:
17402  * @self: a #ClutterActor
17403  * @name: the name of the transition to remove
17404  *
17405  * Removes the transition stored inside a #ClutterActor using @name
17406  * identifier.
17407  *
17408  * If the transition is currently in progress, it will be stopped.
17409  *
17410  * This function releases the reference acquired when the transition
17411  * was added to the #ClutterActor.
17412  *
17413  * Since: 1.10
17414  */
17415 void
17416 clutter_actor_remove_transition (ClutterActor *self,
17417                                  const char   *name)
17418 {
17419   const ClutterAnimationInfo *info;
17420
17421   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17422   g_return_if_fail (name != NULL);
17423
17424   info = _clutter_actor_get_animation_info_or_defaults (self);
17425
17426   if (info->transitions == NULL)
17427     return;
17428
17429   g_hash_table_remove (info->transitions, name);
17430 }
17431
17432 /**
17433  * clutter_actor_remove_all_transitions:
17434  * @self: a #ClutterActor
17435  *
17436  * Removes all transitions associated to @self.
17437  *
17438  * Since: 1.10
17439  */
17440 void
17441 clutter_actor_remove_all_transitions (ClutterActor *self)
17442 {
17443   const ClutterAnimationInfo *info;
17444
17445   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17446
17447   info = _clutter_actor_get_animation_info_or_defaults (self);
17448   if (info->transitions == NULL)
17449     return;
17450
17451   g_hash_table_remove_all (info->transitions);
17452 }
17453
17454 /**
17455  * clutter_actor_set_easing_duration:
17456  * @self: a #ClutterActor
17457  * @msecs: the duration of the easing, or %NULL
17458  *
17459  * Sets the duration of the tweening for animatable properties
17460  * of @self for the current easing state.
17461  *
17462  * Since: 1.10
17463  */
17464 void
17465 clutter_actor_set_easing_duration (ClutterActor *self,
17466                                    guint         msecs)
17467 {
17468   ClutterAnimationInfo *info;
17469
17470   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17471
17472   info = _clutter_actor_get_animation_info (self);
17473
17474   if (info->cur_state == NULL)
17475     {
17476       g_warning ("You must call clutter_actor_save_easing_state() prior "
17477                  "to calling clutter_actor_set_easing_duration().");
17478       return;
17479     }
17480
17481   if (info->cur_state->easing_duration != msecs)
17482     info->cur_state->easing_duration = msecs;
17483 }
17484
17485 /**
17486  * clutter_actor_get_easing_duration:
17487  * @self: a #ClutterActor
17488  *
17489  * Retrieves the duration of the tweening for animatable
17490  * properties of @self for the current easing state.
17491  *
17492  * Return value: the duration of the tweening, in milliseconds
17493  *
17494  * Since: 1.10
17495  */
17496 guint
17497 clutter_actor_get_easing_duration (ClutterActor *self)
17498 {
17499   const ClutterAnimationInfo *info;
17500
17501   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17502
17503   info = _clutter_actor_get_animation_info_or_defaults (self);
17504
17505   if (info->cur_state != NULL)
17506     return info->cur_state->easing_duration;
17507
17508   return 0;
17509 }
17510
17511 /**
17512  * clutter_actor_set_easing_mode:
17513  * @self: a #ClutterActor
17514  * @mode: an easing mode, excluding %CLUTTER_CUSTOM_MODE
17515  *
17516  * Sets the easing mode for the tweening of animatable properties
17517  * of @self.
17518  *
17519  * Since: 1.10
17520  */
17521 void
17522 clutter_actor_set_easing_mode (ClutterActor         *self,
17523                                ClutterAnimationMode  mode)
17524 {
17525   ClutterAnimationInfo *info;
17526
17527   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17528   g_return_if_fail (mode != CLUTTER_CUSTOM_MODE);
17529   g_return_if_fail (mode < CLUTTER_ANIMATION_LAST);
17530
17531   info = _clutter_actor_get_animation_info (self);
17532
17533   if (info->cur_state == NULL)
17534     {
17535       g_warning ("You must call clutter_actor_save_easing_state() prior "
17536                  "to calling clutter_actor_set_easing_mode().");
17537       return;
17538     }
17539
17540   if (info->cur_state->easing_mode != mode)
17541     info->cur_state->easing_mode = mode;
17542 }
17543
17544 /**
17545  * clutter_actor_get_easing_mode:
17546  * @self: a #ClutterActor
17547  *
17548  * Retrieves the easing mode for the tweening of animatable properties
17549  * of @self for the current easing state.
17550  *
17551  * Return value: an easing mode
17552  *
17553  * Since: 1.10
17554  */
17555 ClutterAnimationMode
17556 clutter_actor_get_easing_mode (ClutterActor *self)
17557 {
17558   const ClutterAnimationInfo *info;
17559
17560   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), CLUTTER_EASE_OUT_CUBIC);
17561
17562   info = _clutter_actor_get_animation_info_or_defaults (self);
17563
17564   if (info->cur_state != NULL)
17565     return info->cur_state->easing_mode;
17566
17567   return CLUTTER_EASE_OUT_CUBIC;
17568 }
17569
17570 /**
17571  * clutter_actor_set_easing_delay:
17572  * @self: a #ClutterActor
17573  * @msecs: the delay before the start of the tweening, in milliseconds
17574  *
17575  * Sets the delay that should be applied before tweening animatable
17576  * properties.
17577  *
17578  * Since: 1.10
17579  */
17580 void
17581 clutter_actor_set_easing_delay (ClutterActor *self,
17582                                 guint         msecs)
17583 {
17584   ClutterAnimationInfo *info;
17585
17586   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17587
17588   info = _clutter_actor_get_animation_info (self);
17589
17590   if (info->cur_state == NULL)
17591     {
17592       g_warning ("You must call clutter_actor_save_easing_state() prior "
17593                  "to calling clutter_actor_set_easing_delay().");
17594       return;
17595     }
17596
17597   if (info->cur_state->easing_delay != msecs)
17598     info->cur_state->easing_delay = msecs;
17599 }
17600
17601 /**
17602  * clutter_actor_get_easing_delay:
17603  * @self: a #ClutterActor
17604  *
17605  * Retrieves the delay that should be applied when tweening animatable
17606  * properties.
17607  *
17608  * Return value: a delay, in milliseconds
17609  *
17610  * Since: 1.10
17611  */
17612 guint
17613 clutter_actor_get_easing_delay (ClutterActor *self)
17614 {
17615   const ClutterAnimationInfo *info;
17616
17617   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), 0);
17618
17619   info = _clutter_actor_get_animation_info_or_defaults (self);
17620
17621   if (info->cur_state != NULL)
17622     return info->cur_state->easing_delay;
17623
17624   return 0;
17625 }
17626
17627 /**
17628  * clutter_actor_get_transition:
17629  * @self: a #ClutterActor
17630  * @name: the name of the transition
17631  *
17632  * Retrieves the #ClutterTransition of a #ClutterActor by using the
17633  * transition @name.
17634  *
17635  * Transitions created for animatable properties use the name of the
17636  * property itself, for instance the code below:
17637  *
17638  * |[
17639  *   clutter_actor_set_easing_duration (actor, 1000);
17640  *   clutter_actor_set_rotation (actor, CLUTTER_Y_AXIS, 360.0, x, y, z);
17641  *
17642  *   transition = clutter_actor_get_transition (actor, "rotation-angle-y");
17643  *   g_signal_connect (transition, "completed",
17644  *                     G_CALLBACK (on_transition_complete),
17645  *                     actor);
17646  * ]|
17647  *
17648  * will call the <function>on_transition_complete</function> callback when
17649  * the transition is complete.
17650  *
17651  * Return value: (transfer none): a #ClutterTransition, or %NULL is none
17652  *   was found to match the passed name; the returned instance is owned
17653  *   by Clutter and it should not be freed
17654  *
17655  * Since: 1.10
17656  */
17657 ClutterTransition *
17658 clutter_actor_get_transition (ClutterActor *self,
17659                               const char   *name)
17660 {
17661   TransitionClosure *clos;
17662   const ClutterAnimationInfo *info;
17663
17664   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17665   g_return_val_if_fail (name != NULL, NULL);
17666
17667   info = _clutter_actor_get_animation_info_or_defaults (self);
17668   if (info->transitions == NULL)
17669     return NULL;
17670
17671   clos = g_hash_table_lookup (info->transitions, name);
17672   if (clos == NULL)
17673     return NULL;
17674
17675   return clos->transition;
17676 }
17677
17678 /**
17679  * clutter_actor_save_easing_state:
17680  * @self: a #ClutterActor
17681  *
17682  * Saves the current easing state for animatable properties, and creates
17683  * a new state with the default values for easing mode and duration.
17684  *
17685  * Since: 1.10
17686  */
17687 void
17688 clutter_actor_save_easing_state (ClutterActor *self)
17689 {
17690   ClutterAnimationInfo *info;
17691   AState new_state;
17692
17693   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17694
17695   info = _clutter_actor_get_animation_info (self);
17696
17697   if (info->states == NULL)
17698     info->states = g_array_new (FALSE, FALSE, sizeof (AState));
17699
17700   new_state.easing_mode = CLUTTER_EASE_OUT_CUBIC;
17701   new_state.easing_duration = 250;
17702   new_state.easing_delay = 0;
17703
17704   g_array_append_val (info->states, new_state);
17705
17706   info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17707 }
17708
17709 /**
17710  * clutter_actor_restore_easing_state:
17711  * @self: a #ClutterActor
17712  *
17713  * Restores the easing state as it was prior to a call to
17714  * clutter_actor_save_easing_state().
17715  *
17716  * Since: 1.10
17717  */
17718 void
17719 clutter_actor_restore_easing_state (ClutterActor *self)
17720 {
17721   ClutterAnimationInfo *info;
17722
17723   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17724
17725   info = _clutter_actor_get_animation_info (self);
17726
17727   if (info->states == NULL)
17728     {
17729       g_critical ("The function clutter_actor_restore_easing_state() has "
17730                   "called without a previous call to "
17731                   "clutter_actor_save_easing_state().");
17732       return;
17733     }
17734
17735   g_array_remove_index (info->states, info->states->len - 1);
17736
17737   if (info->states->len > 0)
17738     info->cur_state = &g_array_index (info->states, AState, info->states->len - 1);
17739   else
17740     {
17741       g_array_unref (info->states);
17742       info->states = NULL;
17743       info->cur_state = NULL;
17744     }
17745 }
17746
17747 /**
17748  * clutter_actor_set_content:
17749  * @self: a #ClutterActor
17750  * @content: (allow-none): a #ClutterContent, or %NULL
17751  *
17752  * Sets the contents of a #ClutterActor.
17753  *
17754  * Since: 1.10
17755  */
17756 void
17757 clutter_actor_set_content (ClutterActor   *self,
17758                            ClutterContent *content)
17759 {
17760   ClutterActorPrivate *priv;
17761
17762   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17763   g_return_if_fail (content == NULL || CLUTTER_IS_CONTENT (content));
17764
17765   priv = self->priv;
17766
17767   if (priv->content != NULL)
17768     {
17769       _clutter_content_detached (priv->content, self);
17770       g_clear_object (&priv->content);
17771     }
17772
17773   priv->content = content;
17774
17775   if (priv->content != NULL)
17776     {
17777       g_object_ref (priv->content);
17778       _clutter_content_attached (priv->content, self);
17779     }
17780
17781   /* given that the content is always painted within the allocation,
17782    * we only need to queue a redraw here
17783    */
17784   clutter_actor_queue_redraw (self);
17785
17786   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT]);
17787
17788   /* if the content gravity is not resize-fill, and the new content has a
17789    * different preferred size than the previous one, then the content box
17790    * may have been changed. since we compute that lazily, we just notify
17791    * here, and let whomever watches :content-box do whatever they need to
17792    * do.
17793    */
17794   if (priv->content_gravity != CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17795     g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_BOX]);
17796 }
17797
17798 /**
17799  * clutter_actor_get_content:
17800  * @self: a #ClutterActor
17801  *
17802  * Retrieves the contents of @self.
17803  *
17804  * Return value: (transfer none): a pointer to the #ClutterContent instance,
17805  *   or %NULL if none was set
17806  *
17807  * Since: 1.10
17808  */
17809 ClutterContent *
17810 clutter_actor_get_content (ClutterActor *self)
17811 {
17812   g_return_val_if_fail (CLUTTER_IS_ACTOR (self), NULL);
17813
17814   return self->priv->content;
17815 }
17816
17817 /**
17818  * clutter_actor_set_content_gravity:
17819  * @self: a #ClutterActor
17820  * @gravity: the #ClutterContentGravity
17821  *
17822  * Sets the gravity of the #ClutterContent used by @self.
17823  *
17824  * See the description of the #ClutterActor:content-gravity property for
17825  * more information.
17826  *
17827  * The #ClutterActor:content-gravity property is animatable.
17828  *
17829  * Since: 1.10
17830  */
17831 void
17832 clutter_actor_set_content_gravity (ClutterActor *self,
17833                                    ClutterContentGravity  gravity)
17834 {
17835   ClutterActorPrivate *priv;
17836
17837   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17838
17839   priv = self->priv;
17840
17841   if (priv->content_gravity == gravity)
17842     return;
17843
17844   priv->content_box_valid = FALSE;
17845
17846   if (_clutter_actor_get_transition (self, obj_props[PROP_CONTENT_BOX]) == NULL)
17847     {
17848       ClutterActorBox from_box, to_box;
17849
17850       clutter_actor_get_content_box (self, &from_box);
17851
17852       priv->content_gravity = gravity;
17853
17854       clutter_actor_get_content_box (self, &to_box);
17855
17856       _clutter_actor_create_transition (self, obj_props[PROP_CONTENT_BOX],
17857                                         &from_box,
17858                                         &to_box);
17859     }
17860   else
17861     {
17862       ClutterActorBox to_box;
17863
17864       priv->content_gravity = gravity;
17865
17866       clutter_actor_get_content_box (self, &to_box);
17867
17868       _clutter_actor_update_transition (self, obj_props[PROP_CONTENT_BOX],
17869                                         &to_box);
17870     }
17871
17872   clutter_actor_queue_redraw (self);
17873
17874   g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CONTENT_GRAVITY]);
17875 }
17876
17877 /**
17878  * clutter_actor_get_content_gravity:
17879  * @self: a #ClutterActor
17880  *
17881  * Retrieves the content gravity as set using
17882  * clutter_actor_get_content_gravity().
17883  *
17884  * Return value: the content gravity
17885  *
17886  * Since: 1.10
17887  */
17888 ClutterContentGravity
17889 clutter_actor_get_content_gravity (ClutterActor *self)
17890 {
17891   g_return_val_if_fail (CLUTTER_IS_ACTOR (self),
17892                         CLUTTER_CONTENT_GRAVITY_RESIZE_FILL);
17893
17894   return self->priv->content_gravity;
17895 }
17896
17897 /**
17898  * clutter_actor_get_content_box:
17899  * @self: a #ClutterActor
17900  * @box: (out caller-allocates): the return location for the bounding
17901  *   box for the #ClutterContent
17902  *
17903  * Retrieves the bounding box for the #ClutterContent of @self.
17904  *
17905  * The bounding box is relative to the actor's allocation.
17906  *
17907  * If no #ClutterContent is set for @self, or if @self has not been
17908  * allocated yet, then the result is undefined.
17909  *
17910  * The content box is guaranteed to be, at most, as big as the allocation
17911  * of the #ClutterActor.
17912  *
17913  * If the #ClutterContent used by the actor has a preferred size, then
17914  * it is possible to modify the content box by using the
17915  * #ClutterActor:content-gravity property.
17916  *
17917  * Since: 1.10
17918  */
17919 void
17920 clutter_actor_get_content_box (ClutterActor    *self,
17921                                ClutterActorBox *box)
17922 {
17923   ClutterActorPrivate *priv;
17924   gfloat content_w, content_h;
17925   gfloat alloc_w, alloc_h;
17926
17927   g_return_if_fail (CLUTTER_IS_ACTOR (self));
17928   g_return_if_fail (box != NULL);
17929
17930   priv = self->priv;
17931
17932   box->x1 = 0.f;
17933   box->y1 = 0.f;
17934   box->x2 = priv->allocation.x2 - priv->allocation.x1;
17935   box->y2 = priv->allocation.y2 - priv->allocation.y1;
17936
17937   if (priv->content_box_valid)
17938     {
17939       *box = priv->content_box;
17940       return;
17941     }
17942
17943   /* no need to do any more work */
17944   if (priv->content_gravity == CLUTTER_CONTENT_GRAVITY_RESIZE_FILL)
17945     return;
17946
17947   if (priv->content == NULL)
17948     return;
17949
17950   /* if the content does not have a preferred size then there is
17951    * no point in computing the content box
17952    */
17953   if (!clutter_content_get_preferred_size (priv->content,
17954                                            &content_w,
17955                                            &content_h))
17956     return;
17957
17958   alloc_w = box->x2;
17959   alloc_h = box->y2;
17960
17961   switch (priv->content_gravity)
17962     {
17963     case CLUTTER_CONTENT_GRAVITY_TOP_LEFT:
17964       box->x2 = box->x1 + MIN (content_w, alloc_w);
17965       box->y2 = box->y1 + MIN (content_h, alloc_h);
17966       break;
17967
17968     case CLUTTER_CONTENT_GRAVITY_TOP:
17969       if (alloc_w > content_w)
17970         {
17971           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17972           box->x2 = box->x1 + content_w;
17973         }
17974       box->y2 = box->y1 + MIN (content_h, alloc_h);
17975       break;
17976
17977     case CLUTTER_CONTENT_GRAVITY_TOP_RIGHT:
17978       if (alloc_w > content_w)
17979         {
17980           box->x1 += (alloc_w - content_w);
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_LEFT:
17987       box->x2 = box->x1 + MIN (content_w, alloc_w);
17988       if (alloc_h > content_h)
17989         {
17990           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
17991           box->y2 = box->y1 + content_h;
17992         }
17993       break;
17994
17995     case CLUTTER_CONTENT_GRAVITY_CENTER:
17996       if (alloc_w > content_w)
17997         {
17998           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
17999           box->x2 = box->x1 + content_w;
18000         }
18001       if (alloc_h > content_h)
18002         {
18003           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18004           box->y2 = box->y1 + content_h;
18005         }
18006       break;
18007
18008     case CLUTTER_CONTENT_GRAVITY_RIGHT:
18009       if (alloc_w > content_w)
18010         {
18011           box->x1 += (alloc_w - content_w);
18012           box->x2 = box->x1 + content_w;
18013         }
18014       if (alloc_h > content_h)
18015         {
18016           box->y1 += ceilf ((alloc_h - content_h) / 2.0);
18017           box->y2 = box->y1 + content_h;
18018         }
18019       break;
18020
18021     case CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT:
18022       box->x2 = box->x1 + MIN (content_w, alloc_w);
18023       if (alloc_h > content_h)
18024         {
18025           box->y1 += (alloc_h - content_h);
18026           box->y2 = box->y1 + content_h;
18027         }
18028       break;
18029
18030     case CLUTTER_CONTENT_GRAVITY_BOTTOM:
18031       if (alloc_w > content_w)
18032         {
18033           box->x1 += ceilf ((alloc_w - content_w) / 2.0);
18034           box->x2 = box->x1 + content_w;
18035         }
18036       if (alloc_h > content_h)
18037         {
18038           box->y1 += (alloc_h - content_h);
18039           box->y2 = box->y1 + content_h;
18040         }
18041       break;
18042
18043     case CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT:
18044       if (alloc_w > content_w)
18045         {
18046           box->x1 += (alloc_w - content_w);
18047           box->x2 = box->x1 + content_w;
18048         }
18049       if (alloc_h > content_h)
18050         {
18051           box->y1 += (alloc_h - content_h);
18052           box->y2 = box->y1 + content_h;
18053         }
18054       break;
18055
18056     case CLUTTER_CONTENT_GRAVITY_RESIZE_FILL:
18057       g_assert_not_reached ();
18058       break;
18059
18060     case CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT:
18061       {
18062         double r_c = content_w / content_h;
18063         double r_a = alloc_w / alloc_h;
18064
18065         if (r_c >= 1.0)
18066           {
18067             if (r_a >= 1.0)
18068               {
18069                 box->x1 = 0.f;
18070                 box->x2 = alloc_w;
18071
18072                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18073                 box->y2 = box->y1 + (alloc_w * r_c);
18074               }
18075             else
18076               {
18077                 box->y1 = 0.f;
18078                 box->y2 = alloc_h;
18079
18080                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18081                 box->x2 = box->x1 + (alloc_h * r_c);
18082               }
18083           }
18084         else
18085           {
18086             if (r_a >= 1.0)
18087               {
18088                 box->y1 = 0.f;
18089                 box->y2 = alloc_h;
18090
18091                 box->x1 = (alloc_w - (alloc_h * r_c)) / 2.0f;
18092                 box->x2 = box->x1 + (alloc_h * r_c);
18093               }
18094             else
18095               {
18096                 box->x1 = 0.f;
18097                 box->x2 = alloc_w;
18098
18099                 box->y1 = (alloc_h - (alloc_w * r_c)) / 2.0f;
18100                 box->y2 = box->y1 + (alloc_w * r_c);
18101               }
18102           }
18103       }
18104       break;
18105     }
18106 }
18107
18108 /**
18109  * clutter_actor_set_content_scaling_filters:
18110  * @self: a #ClutterActor
18111  * @min_filter: the minification filter for the content
18112  * @mag_filter: the magnification filter for the content
18113  *
18114  * Sets the minification and magnification filter to be applied when
18115  * scaling the #ClutterActor:content of a #ClutterActor.
18116  *
18117  * The #ClutterActor:minification-filter will be used when reducing
18118  * the size of the content; the #ClutterActor:magnification-filter
18119  * will be used when increasing the size of the content.
18120  *
18121  * Since: 1.10
18122  */
18123 void
18124 clutter_actor_set_content_scaling_filters (ClutterActor         *self,
18125                                            ClutterScalingFilter  min_filter,
18126                                            ClutterScalingFilter  mag_filter)
18127 {
18128   ClutterActorPrivate *priv;
18129   gboolean changed;
18130   GObject *obj;
18131
18132   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18133
18134   priv = self->priv;
18135   obj = G_OBJECT (self);
18136
18137   g_object_freeze_notify (obj);
18138
18139   changed = FALSE;
18140
18141   if (priv->min_filter != min_filter)
18142     {
18143       priv->min_filter = min_filter;
18144       changed = TRUE;
18145
18146       g_object_notify_by_pspec (obj, obj_props[PROP_MINIFICATION_FILTER]);
18147     }
18148
18149   if (priv->mag_filter != mag_filter)
18150     {
18151       priv->mag_filter = mag_filter;
18152       changed = TRUE;
18153
18154       g_object_notify_by_pspec (obj, obj_props[PROP_MAGNIFICATION_FILTER]);
18155     }
18156
18157   if (changed)
18158     clutter_actor_queue_redraw (self);
18159
18160   g_object_thaw_notify (obj);
18161 }
18162
18163 /**
18164  * clutter_actor_get_content_scaling_filters:
18165  * @self: a #ClutterActor
18166  * @min_filter: (out) (allow-none): return location for the minification
18167  *   filter, or %NULL
18168  * @mag_filter: (out) (allow-none): return location for the magnification
18169  *   filter, or %NULL
18170  *
18171  * Retrieves the values set using clutter_actor_set_content_scaling_filters().
18172  *
18173  * Since: 1.10
18174  */
18175 void
18176 clutter_actor_get_content_scaling_filters (ClutterActor         *self,
18177                                            ClutterScalingFilter *min_filter,
18178                                            ClutterScalingFilter *mag_filter)
18179 {
18180   g_return_if_fail (CLUTTER_IS_ACTOR (self));
18181
18182   if (min_filter != NULL)
18183     *min_filter = self->priv->min_filter;
18184
18185   if (mag_filter != NULL)
18186     *mag_filter = self->priv->mag_filter;
18187 }